使用Python開發(fā)在線編輯器
更新時間:2025年02月05日 10:19:35 作者:mosquito_lover1
這篇文章主要為大家詳細介紹了如何使用Python開發(fā)一個在線編輯器,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以了解一下
實現(xiàn)效果
完整代碼
from flask import Flask, render_template, request, jsonify import sys from io import StringIO import contextlib import subprocess import importlib import threading import time import ast import re app = Flask(__name__) RESTRICTED_PACKAGES = { 'tkinter': '抱歉,在線編譯器不支持 tkinter,因為它需要圖形界面環(huán)境。請在本地運行需要GUI的代碼。', 'tk': '抱歉,在線編譯器不支持 tk/tkinter,因為它需要圖形界面環(huán)境。請在本地運行需要GUI的代碼。', 'pygame': 'pygame將被轉(zhuǎn)換為Web版本運行' # 不再限制pygame,而是轉(zhuǎn)換它 } def convert_tkinter_to_web(code): """將tkinter代碼轉(zhuǎn)換為Web等效實現(xiàn)""" # 解析Python代碼 tree = ast.parse(code) # 提取窗口屬性 window_props = { 'title': 'Python GUI', 'width': '700', 'height': '500', 'buttons': [], 'labels': [], 'entries': [], 'layout': [] } # 用于存儲函數(shù)定義 functions = {} # 首先收集所有函數(shù)定義 for node in ast.walk(tree): if isinstance(node, ast.FunctionDef): functions[node.name] = ast.unparse(node) # 分析代碼中的tkinter組件 for node in ast.walk(tree): if isinstance(node, ast.Assign): if isinstance(node.value, ast.Call): # 提取窗口標題 if hasattr(node.value.func, 'attr') and node.value.func.attr == 'Tk': for subnode in ast.walk(tree): if isinstance(subnode, ast.Call) and hasattr(subnode.func, 'attr'): if subnode.func.attr == 'title' and len(subnode.args) > 0: window_props['title'] = ast.literal_eval(subnode.args[0]) elif subnode.func.attr == 'geometry' and len(subnode.args) > 0: geom = ast.literal_eval(subnode.args[0]) match = re.match(r'(\d+)x(\d+)', geom) if match: window_props['width'] = match.group(1) window_props['height'] = match.group(2) # 提取按鈕 elif hasattr(node.value.func, 'attr') and node.value.func.attr == 'Button': button = {'text': 'Button', 'command': None} for kw in node.value.keywords: if kw.arg == 'text': button['text'] = ast.literal_eval(kw.value) elif kw.arg == 'command': # 處理不同類型的command if isinstance(kw.value, ast.Name): # 簡單的函數(shù)名 button['command'] = kw.value.id elif isinstance(kw.value, ast.Lambda): # Lambda表達式 button['command'] = f"lambda_{len(window_props['buttons'])}" functions[button['command']] = ast.unparse(kw.value) else: # 其他情況,嘗試轉(zhuǎn)換為字符串 try: button['command'] = ast.unparse(kw.value) except: button['command'] = 'unknown_command' window_props['buttons'].append(button) # 提取標簽 elif hasattr(node.value.func, 'attr') and node.value.func.attr == 'Label': label = {'text': ''} for kw in node.value.keywords: if kw.arg == 'text': try: label['text'] = ast.literal_eval(kw.value) except: # 如果不是字面量,嘗試直接轉(zhuǎn)換為字符串 label['text'] = ast.unparse(kw.value) window_props['labels'].append(label) # 提取輸入框 elif hasattr(node.value.func, 'attr') and node.value.func.attr == 'Entry': try: entry_id = node.targets[0].id except: entry_id = f"entry_{len(window_props['entries'])}" window_props['entries'].append({'id': entry_id}) # 生成Web等效代碼 web_code = f""" <!DOCTYPE html> <div class="tk-window" style="width: {window_props['width']}px; height: {window_props['height']}px;"> <div class="tk-title-bar">{window_props['title']}</div> <div class="tk-content"> """ # 添加標簽 for label in window_props['labels']: web_code += f' <div class="tk-label">{label["text"]}</div>\n' # 添加輸入框 for entry in window_props['entries']: web_code += f' <input type="text" class="tk-entry" id="{entry["id"]}">\n' # 添加按鈕 for button in window_props['buttons']: command = button['command'] if button['command'] else '' web_code += f' <button class="tk-button" onclick="tkButtonClick(\'{command}\')">{button["text"]}</button>\n' web_code += """ </div> </div> <script> window.pythonFunctions = { """ # 添加Python函數(shù)定義 for func_name, func_code in functions.items(): web_code += f" '{func_name}': {func_code},\n" web_code += """}; </script> """ return web_code def convert_pygame_to_web(code): """將pygame代碼轉(zhuǎn)換為Web Canvas實現(xiàn)""" web_code = """ <canvas id="pygame-canvas" style="border: 1px solid #000;"></canvas> <script> const canvas = document.getElementById('pygame-canvas'); const ctx = canvas.getContext('2d'); // 設置畫布大小 canvas.width = 800; canvas.height = 600; // 模擬 pygame 的基本功能 const pygame = { display: { set_mode: (size) => { canvas.width = size[0]; canvas.height = size[1]; return canvas; }, update: () => { // Canvas 自動更新 }, flip: () => { // Canvas 自動更新 } }, draw: { rect: (surface, color, rect) => { ctx.fillStyle = `rgb(${color[0]},${color[1]},${color[2]})`; ctx.fillRect(rect[0], rect[1], rect[2], rect[3]); }, circle: (surface, color, pos, radius) => { ctx.beginPath(); ctx.fillStyle = `rgb(${color[0]},${color[1]},${color[2]})`; ctx.arc(pos[0], pos[1], radius, 0, Math.PI * 2); ctx.fill(); } }, event: { get: () => [], // 簡化的事件處理 pump: () => {} }, init: () => {}, quit: () => {}, time: { Clock: function() { return { tick: (fps) => 1000/fps }; } } }; // 轉(zhuǎn)換后的Python代碼 function runGame() { try { // 這里將插入轉(zhuǎn)換后的游戲代碼 %PYTHON_CODE% } catch (error) { console.error('Game error:', error); } } // 啟動游戲循環(huán) runGame(); </script> """ # 處理 Python 代碼 try: tree = ast.parse(code) # 轉(zhuǎn)換 Python 代碼為 JavaScript js_code = convert_pygame_code_to_js(tree) web_code = web_code.replace('%PYTHON_CODE%', js_code) return web_code except Exception as e: return f"<div class='error'>轉(zhuǎn)換錯誤: {str(e)}</div>" def convert_pygame_code_to_js(tree): """將 Python AST 轉(zhuǎn)換為 JavaScript 代碼""" js_code = [] for node in ast.walk(tree): if isinstance(node, ast.Import): continue # 跳過導入語句 elif isinstance(node, ast.Assign): # 轉(zhuǎn)換賦值語句 if hasattr(node.value, 'func') and isinstance(node.value.func, ast.Attribute): if node.value.func.attr == 'set_mode': js_code.append(f"const screen = pygame.display.set_mode([{node.value.args[0].elts[0].n}, {node.value.args[0].elts[1].n}]);") elif isinstance(node, ast.While): # 轉(zhuǎn)換游戲主循環(huán) js_code.append("function gameLoop() {") # ... 處理循環(huán)體 js_code.append(" requestAnimationFrame(gameLoop);") js_code.append("}") js_code.append("gameLoop();") return "\n".join(js_code) def install_package(package): """自動安裝缺失的包""" # 檢查是否是受限制的包 if package.lower() in RESTRICTED_PACKAGES: raise ImportError(RESTRICTED_PACKAGES[package.lower()]) try: importlib.import_module(package) except ImportError: try: # 嘗試使用 pip 安裝包 subprocess.check_call([sys.executable, "-m", "pip", "install", package]) except subprocess.CalledProcessError as e: raise Exception(f"安裝包 {package} 失敗: {str(e)}") def timeout_handler(): """強制終止超時的代碼執(zhí)行""" raise TimeoutError("代碼執(zhí)行超時(最大執(zhí)行時間:5秒)") @app.route('/') def index(): return render_template('index.html') @app.route('/execute', methods=['POST']) def execute_code(): code = request.json.get('code', '') try: # 檢測是否包含pygame代碼 if 'pygame' in code: web_code = convert_pygame_to_web(code) return jsonify({ 'status': 'success', 'output': '', 'gui': web_code }) # 檢測是否包含tkinter代碼 elif 'tkinter' in code or 'tk' in code: web_code = convert_tkinter_to_web(code) return jsonify({ 'status': 'success', 'output': '', 'gui': web_code }) # 非GUI代碼正常執(zhí)行 output_buffer = StringIO() with contextlib.redirect_stdout(output_buffer): exec(code, globals(), {}) output = output_buffer.getvalue() return jsonify({ 'status': 'success', 'output': output if output else '程序執(zhí)行完成,沒有輸出' }) except Exception as e: return jsonify({ 'status': 'error', 'output': f'錯誤: {str(e)}' }) if __name__ == '__main__': app.run(debug=True)
以上就是使用Python開發(fā)在線編輯器的詳細內(nèi)容,更多關于Python在線編輯器的資料請關注腳本之家其它相關文章!
相關文章
gethostbyaddr在Python3中引發(fā)UnicodeDecodeError
本文介紹了gethostbyaddr()在Python?3中引發(fā)UnicodeDecodeError的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧2022-05-05python爬取Ajax動態(tài)加載網(wǎng)頁過程解析
這篇文章主要介紹了python爬取Ajax動態(tài)加載網(wǎng)頁過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-09-09在交互式環(huán)境中執(zhí)行Python程序過程詳解
這篇文章主要介紹了在交互式環(huán)境中執(zhí)行Python程序過程詳解,運行Python腳本程序的方式有多種,目前主要的方式有:交互式環(huán)境運行、命令行窗口運行、開發(fā)工具上運行等,其中在不同的操作平臺上還互不相同,需要的朋友可以參考下2019-07-07詳解pyqt中解決國際化tr()函數(shù)不起作用的問題
本文主要介紹了pyqt中解決國際化tr()函數(shù)不起作用的問題,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02Python虛擬環(huán)境管理工具virtualenv詳解
在Python開發(fā)過程中,我們常常需要管理不同項目的依賴,每個項目可能依賴不同版本的Python庫,因此,如何有效管理這些庫成為了開發(fā)者日常工作中不可忽視的問題,需要的朋友可以參考下2024-12-12