使用Pyodide与Web Worker在浏览器中获取Python执行结果字符串
解决Pyodide Worker捕获Python输出并返回的问题
问题核心是当前代码仅返回执行状态提示,未捕获Python代码中print等输出到标准流的内容。需要通过重定向Pyodide的stdout/stderr来收集输出,再返回给主线程。
修改worker.js代码
这是关键修改点,需要在Pyodide中捕获标准输出和错误:
importScripts("https://cdn.jsdelivr.net/pyodide/v0.25.0/full/pyodide.js"); async function loadPyodideAndPackages() { self.pyodide = await loadPyodide({ "indexURL" : "https://cdn.jsdelivr.net/pyodide/v0.25.0/full/", }); // 初始化输出收集器 self.outputBuffer = []; // 重定向stdout self.pyodide.setStdout({ write: (text) => { self.outputBuffer.push(text); }, flush: () => {} }); // 重定向stderr self.pyodide.setStderr({ write: (text) => { self.outputBuffer.push(`[ERROR] ${text}`); }, flush: () => {} }); // await self.pyodide.loadPackage(["numpy"]); } let pyodideReadyPromise = loadPyodideAndPackages(); self.onmessage = async (event) => { await pyodideReadyPromise; const { id, pythonCode, context } = event.data; // 清空之前的输出缓存 self.outputBuffer = []; // 将上下文变量注入到Pyodide的Python环境 for (const key in context) { self.pyodide.globals.set(key, context[key]); } try { // 运行Python代码 await self.pyodide.runPythonAsync(pythonCode); // 将收集到的输出拼接成字符串返回 const output = self.outputBuffer.join(""); postMessage({ id, result: output || "Execution complete" }); } catch (error) { // 捕获异常时,也带上已收集的输出 const output = self.outputBuffer.join(""); const errorMsg = output ? `${output}\n[EXCEPTION] ${error.message}` : error.message; postMessage({ id, error: errorMsg }); } };
可选微调main-worker.js
如果需要处理空结果的情况,可在runPythonCode中增加默认返回逻辑:
// main-worker.js async function runPythonCode(pythonCode, context) { try { const { result, error } = await asyncRun(pythonCode, context); if (result) { return result.toString() } else if (error) { return error } // 添加无输出时的默认返回 return "No output generated" } catch (e) { console.error("Error communicating with the worker:", e); return `Worker communication error: ${e.message}`; } }
测试与使用
修改后,运行print('Hello, World!')时,result变量会拿到字符串Hello, World!\n,你可以将其插入到目标div中:
// test-code中更新点击事件逻辑 $(element).find(".run-code:first").click( async function() { let current_code = "print('Hello, World!')" let result = await runPythonCode(current_code) console.log("Run clicked", result) // 将结果插入到指定div $(element).find(".result-display").text(result); } )
关键说明
- 通过
pyodide.setStdout和pyodide.setStderr可以捕获Python代码的所有标准输出和错误输出。 - 每次运行代码前清空输出缓存,避免不同运行的输出混在一起。
- 异常处理时同时返回已收集的输出和异常信息,便于调试。
内容的提问来源于stack exchange,提问作者inquilabee
相关产品推荐
相关产品推荐

