根据@Andreas 的评论回复,您需要使用config
参数 ofloadPyodide
为config.stdout
(和config.stderr
)设置回调函数。
Pyodide 的在线文档没有显示stdout
回调的确切签名,但幸运的是,他们的 github 存储库中有一个 TypeScript 注释文件,其中显示stdout
和stderr
都是(string) => void
.
所以你可以做这样的事情:
免责声明:
- 我之前没有任何使用 Pyodide 的经验。
- 我个人的风格偏好是使用命名函数,包括全局范围的函数,尽管我知道有些人现在对不这样做非常虔诚,嗯,不管你的船是什么...
- 我添加
defer
到<script>
.
- jsDelivr 托管的
pyodide/v0.19.1
脚本没有为我加载,我收到 HTTP 403 错误。其他人也在报告问题。
- 我不建议任何人使用 jsDelivr 或任何其他 JS 托管服务,这些服务与他们托管的脚本或使用它们的网站没有合理的商业模式和/或实际关系。还有更多的原因。
- 即使在 jsDelivr 上没有发生任何可疑的事情,即使您使用
<script integrity="">
正确,也没有任何 CDN 网站会永远存在,之后您的网站就会崩溃。只需自己托管脚本或使用您自己负责的 CDN帐户。
// Using `var` promotes these variables to window properties which makes it easier to access them in certain situations.
var py = null;
var pythonOutputUL = null;
// The pyodide.js <script> is marked with `defer` so it won't block the page load, which also means it can't be used until the DOMContentLoaded event.
function pythonConsoleStdOut( text ) {
console.log( "Python stdout: %o", text );
appendPythonOutputMessage( 'stdout', text );
}
function pythonConsoleStdErr( text ) {
console.error( "Python stderr: %o", text );
appendPythonOutputMessage( 'stderr', text );
}
function appendPythonOutputMessage( className, text ) {
const messageLI = document.createElement('li');
messageLI.classList.add( className );
messageLI.dataset['dt'] = new Date().toString();
messageLI.textContent = text;
window.pythonOutputUL.appendChild( messageLI );
}
window.addEventListener( 'DOMContentLoaded', loadPython );
const pyodideConfig = {
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.19.1/full/",
stdout : pythonConsoleStdOut,
stderr : pythonConsoleStdErr
};
async function loadPython() {
window.pythonOutputUL = document.getElementById( 'pythonOutputUL' );
try {
window.py = await loadPyodide( pyodideConfig );
}
catch( err ) {
debugger;
console.error( "Pyodide's loadPyodide threw an error: %o", err );
appendPythonOutputMessage( "Failed to load Pyodide: " + ( err || '' ).toString() );
return;
}
document.getElementById( 'loadingMessage' ).hidden = true;
document.getElementById( 'codeTextArea' ).disabled = false;
document.getElementById( 'runButton' ).disabled = false;
}
async function run( e ) {
if( !window.py ) throw new Error( "Pyodide isn't loaded yet." );
const pythonScript = document.getElementById( "codeTextArea" ).value;
const button = e.currentTarget;
button.disabled = true;
button.textContent = "Running...";
try {
await window.py.runPythonAsync( /*code:*/ pythonScript, /*globals:*/ { } );
button.textContent = "Run";
}
catch( err ) {
// debugger; // Uncomment at your discretion.
console.error( err );
button.textContent = "Error. See browser console.";
}
finally {
button.disabled = false;
}
}
function onPyodideScriptLoadError( event ) {
debugger;
console.error( "Failed to load Pyodide.js: %o", event );
appendPythonOutputMessage( "Failed to load Pyodide.js. See browser console." );
}
#pythonOutputUL {
font-family: monospace;
}
#pythonOutputUL > li[data-dt]::before {
content: "[" attr(data-dt) "] ";
display: inline;
}
#pythonOutputUL > li.stdout {
border-top: 1px solid #ccc;
}
#pythonOutputUL > li.stderr {
border-top: 1px solid #red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WIDLE - Web IDLE</title>
<script src="https://cdn.jsdelivr.net/pyodide/v0.19.1/full/pyodide.js" defer onerror="onPyodideScriptLoadError(event)"></script>
</head>
<body>
<noscript>Please enable JS to run</noscript>
<p id="loadingMessage">Loading, please wait...</p>
<textarea id="codeTextArea" disabled></textarea>
<button id="runButton" onclick="run(event)" disabled>Run</button>
<ul id="pythonOutputUL">
</ul>
</body>
</html>