使用Python開(kāi)發(fā)在線(xiàn)編輯器
實(shí)現(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': '抱歉,在線(xiàn)編譯器不支持 tkinter,因?yàn)樗枰獔D形界面環(huán)境。請(qǐng)?jiān)诒镜剡\(yùn)行需要GUI的代碼。', 'tk': '抱歉,在線(xiàn)編譯器不支持 tk/tkinter,因?yàn)樗枰獔D形界面環(huán)境。請(qǐng)?jiān)诒镜剡\(yùn)行需要GUI的代碼。', 'pygame': 'pygame將被轉(zhuǎn)換為Web版本運(yùn)行' # 不再限制pygame,而是轉(zhuǎn)換它 } def convert_tkinter_to_web(code): """將tkinter代碼轉(zhuǎn)換為Web等效實(shí)現(xiàn)""" # 解析Python代碼 tree = ast.parse(code) # 提取窗口屬性 window_props = { 'title': 'Python GUI', 'width': '700', 'height': '500', 'buttons': [], 'labels': [], 'entries': [], 'layout': [] } # 用于存儲(chǔ)函數(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): # 提取窗口標(biāo)題 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': # 處理不同類(lèi)型的command if isinstance(kw.value, ast.Name): # 簡(jiǎn)單的函數(shù)名 button['command'] = kw.value.id elif isinstance(kw.value, ast.Lambda): # Lambda表達(dá)式 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) # 提取標(biāo)簽 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"> """ # 添加標(biāo)簽 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實(shí)現(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'); // 設(shè)置畫(huà)布大小 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 自動(dòng)更新 }, flip: () => { // Canvas 自動(dòng)更新 } }, 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: () => [], // 簡(jiǎn)化的事件處理 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); } } // 啟動(dòng)游戲循環(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)換錯(cuò)誤: {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 # 跳過(guò)導(dǎo)入語(yǔ)句 elif isinstance(node, ast.Assign): # 轉(zhuǎn)換賦值語(yǔ)句 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): """自動(dòng)安裝缺失的包""" # 檢查是否是受限制的包 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(): """強(qiáng)制終止超時(shí)的代碼執(zhí)行""" raise TimeoutError("代碼執(zhí)行超時(shí)(最大執(zhí)行時(shí)間:5秒)") @app.route('/') def index(): return render_template('index.html') @app.route('/execute', methods=['POST']) def execute_code(): code = request.json.get('code', '') try: # 檢測(cè)是否包含pygame代碼 if 'pygame' in code: web_code = convert_pygame_to_web(code) return jsonify({ 'status': 'success', 'output': '', 'gui': web_code }) # 檢測(cè)是否包含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í)行完成,沒(méi)有輸出' }) except Exception as e: return jsonify({ 'status': 'error', 'output': f'錯(cuò)誤: {str(e)}' }) if __name__ == '__main__': app.run(debug=True)
以上就是使用Python開(kāi)發(fā)在線(xiàn)編輯器的詳細(xì)內(nèi)容,更多關(guān)于Python在線(xiàn)編輯器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python IDE PyCharm的基本快捷鍵和配置簡(jiǎn)介
這篇文章主要介紹了Python IDE PyCharm的基本快捷鍵和配置簡(jiǎn)介,PyCharm為一個(gè)收費(fèi)的軟件,需要的朋友可以參考下2015-11-11gethostbyaddr在Python3中引發(fā)UnicodeDecodeError
本文介紹了gethostbyaddr()在Python?3中引發(fā)UnicodeDecodeError的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-05-05Python使用樹(shù)狀圖實(shí)現(xiàn)可視化聚類(lèi)詳解
一般情況下,我們都是使用散點(diǎn)圖進(jìn)行聚類(lèi)可視化,但是某些的聚類(lèi)算法可視化時(shí)散點(diǎn)圖并不理想,所以在這篇文章中,我們介紹如何使用樹(shù)狀圖(Dendrograms)對(duì)我們的聚類(lèi)結(jié)果進(jìn)行可視化2023-03-03python爬取Ajax動(dòng)態(tài)加載網(wǎng)頁(yè)過(guò)程解析
這篇文章主要介紹了python爬取Ajax動(dòng)態(tài)加載網(wǎng)頁(yè)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09在交互式環(huán)境中執(zhí)行Python程序過(guò)程詳解
這篇文章主要介紹了在交互式環(huán)境中執(zhí)行Python程序過(guò)程詳解,運(yùn)行Python腳本程序的方式有多種,目前主要的方式有:交互式環(huán)境運(yùn)行、命令行窗口運(yùn)行、開(kāi)發(fā)工具上運(yùn)行等,其中在不同的操作平臺(tái)上還互不相同,需要的朋友可以參考下2019-07-07python接口測(cè)試對(duì)修改密碼接口進(jìn)行壓測(cè)
這篇文章主要為大家介紹了python接口測(cè)試對(duì)修改密碼接口進(jìn)行壓測(cè)的腳本實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07學(xué)python需要去培訓(xùn)機(jī)構(gòu)嗎
在本篇文章里小編給大家整理的是關(guān)于學(xué)python是否需要去培訓(xùn)機(jī)構(gòu)的相關(guān)內(nèi)容,有需要的朋友們可以閱讀下。2020-07-07詳解pyqt中解決國(guó)際化tr()函數(shù)不起作用的問(wèn)題
本文主要介紹了pyqt中解決國(guó)際化tr()函數(shù)不起作用的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02使用Python實(shí)現(xiàn)一個(gè)圖片查看器
這篇文章主要為大家詳細(xì)介紹了如何使用Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的圖片查看器,并且可以實(shí)現(xiàn)圖片放大與縮小功能,感興趣的小伙伴可以了解下2025-02-02Python虛擬環(huán)境管理工具virtualenv詳解
在Python開(kāi)發(fā)過(guò)程中,我們常常需要管理不同項(xiàng)目的依賴(lài),每個(gè)項(xiàng)目可能依賴(lài)不同版本的Python庫(kù),因此,如何有效管理這些庫(kù)成為了開(kāi)發(fā)者日常工作中不可忽視的問(wèn)題,需要的朋友可以參考下2024-12-12