当前位置: 首页 > 科技观察

使用WebAssembly在浏览器中运行Python

时间:2023-03-16 17:06:19 科技观察

Python社区长期以来一直在讨论如何使Python成为网络浏览器中流行的编程语言。然而,网络浏览器实际上只支持一种编程语言:JavaScript。随着网络技术的发展,我们把越来越多的程序放到了网络上,比如游戏、数据科学可视化、音视频编辑软件等。这意味着我们为网络带来了繁重的计算——这不是JavaScript的设计目标。所有这些挑战都提出了对可以提供快速、可移植、紧凑和安全代码执行的新编程语言的需求。因此,主要的浏览器供应商致力于实现这个想法,并在2017年向世界推出了WebAssembly。在本教程中,我们将了解WebAssembly如何帮助您在浏览器中运行Python代码。需要明确的是,JavaScript本身就是一种强大的编程语言。它只是不适合某些操作。关于这一点,请看JavaScript之父BrendanEich的文章《从ASM.JS到WebAssembly》。我们正在构建什么假设您想教授Python课程。为了使您的课程更加有趣和有趣,您希望在每节课后为您的学生提供一个练习,以便他们可以练习所学内容。这里的问题是学生需要通过安装特定版本的Python、创建和激活虚拟环境以及安装所有必要的包来准备开发环境。这可能需要花费大量时间和精力。也很难对此给出准确的指导,因为每台机器都不一样。虽然您可以创建后端以在Docker容器或AWSLambda函数中运行提交的代码,但您选择保持堆栈简单,将Python编辑器添加到课程内容,并在客户端的Web浏览器中运行Python代码,并将结果显示给用户。这正是您将在本教程中构建的内容。WebAssembly根据MozillaDeveloperNetwork(MDN)文档的定义,WebAssembly(WASM)的定义如下:WebAssembly是一种运行在现代网络浏览器中并提供新的性能特性和效果的新型代码。它不是为手写代码而设计的,而是为C、C++和Rust等低级源语言提供高效的编译目标。因此,WASM让我们可以在浏览器中运行用不同语言(不仅仅是JavaScript)编写的代码,具有以下好处:快速、高效和可移植。它是安全的,因为代码在安全的沙盒执行环境中运行。它可以在客户端运行。所以在我们上面的例子中,我们不需要担心用户在我们的服务器上运行代码,也不需要担心成千上万的学生尝试练习代码,因为代码的执行发生在客户端,在网络浏览器上。WebAssembly并不是为了杀死JavaScript而设计的。它是对JavaScript的补充。当JavaScript不是合适的工具时可以使用它,例如游戏、图像识别和图像/视频编辑等。请参阅WebAssembly.org上的用例,了解您可能想要利用WebAssembly的更多情况。Pyodide本教程使用Pyodide库运行Python代码,它将CPython解释器编译成WebAssembly,并在浏览器的JavaScript环境中运行。它带有一些预装的Python包。你也可以使用Micropip来使用更多的包。HelloWorld使用以下代码创建一个新的HTML文件。在浏览器中打开文件。然后,在浏览器的开发人员工具控制台中,您应该执行以下操作:浏览器!可以看到,最后一行是Python代码在浏览器中执行的结果。让我们快速浏览一下上面的代码。首先,您可以使用CDN或直接从GitHub版本下载并安装Pyodide。loadPyodide加载并初始化Pyodidewasm模块。pyodide.runPython将Python代码作为字符串并返回代码的结果。Pyodide的优势在前面的示例中,您看到了安装和开始使用Pyodide是多么容易。你只需要从CDN导入pyodide.js并通过loadPyodide初始化它。之后,您可以使用pyodide.runPython("yourPythoncode")在浏览器中运行您的Python代码。当您第一次下载Pyodide时,下载量很大,因为您下载的是完整的CPython解释器,但您的浏览器会缓存它,您不需要再次下载。Pyodide上还有一个庞大而活跃的社区。其官网如下:https://pyodide.org/en/stable/你可以看看Pyodide路线图、GitHub上的未解决问题和Gitter社区。Pyodide的局限性第一次加载Pyodide时,需要四到五秒钟(取决于您的连接速度),因为您必须下载一个大约10MB左右的文件。此外,Pyodide代码的运行速度比原生Python慢3到5倍。其他选项一般来说,如果你想在浏览器中运行Python,你有两个选项可用。1.使用转译器将Python转换为JavaScript。Brython、Transcrypt和Skulpt都使用这种方法。2.转换Python运行环境,在浏览器中使用。Pyodide和PyPy.js使用这种方法。选项1和选项2之间的一个主要区别是选项1中提到的库不支持Python包。也就是说,它们的下载大小比选项二中的库小得多,因此它们也更快。在本教程中,我们选择了Pyodide,因为它的语法更简单并且支持Python包。如果您对其他选项感兴趣,请随时查看他们的文档。Python代码编辑器在本节中,我们将创建一个可以在浏览器中运行代码的简单Python编辑器。1.Pyodide2、CodeMirror3、Flask新建工程。$mkdirpython_editor_wasm$cdpython_editor_wasm创建并激活虚拟环境。$python3.10-mvenvenv$sourceenv/bin/activate(env)$安装Flask:(env)$pipinstallFlask在项目的根目录下创建一个名为app.py的文件并添加以下代码。fromflaskimportFlask,render_templateapp=Flask(__name__)@app.route('/')defindex():returnrender_template('index.html')如果__name__=='__main__':app.run(debug=True)在我们项目的根目录下创建一个“templates”文件夹,并在其下添加index.html文件。templates/index.html:在浏览器中运行Python

Run清除历史记录在index.html文件的头部,我们导入了TailwindCSS进行格式化,Pyodide.js0.20.0,以及CodeMirror及其依赖包UI有3个重要的组件:1.Editor,用户可以在这里写Python代码,它是一个带有文本区域的HTML元素,ID为code,我们在初始化codemirror的时候,让它知道我们要使用这个元素作为一个代码编辑器。2.Output。显示代码输出的地方。它是一个textarea元素,id为output。当Pyodide执行Python代码时,它将结果输出到这个元素。我们还在该元素中显示一条错误消息。3.运行按钮。当用户单击此按钮时,我们获取编辑器元素的值并将其作为字符串传递给pyodide.runPython。当pyodide.runPython返回结果时,我们在输出元素中显示它。现在在项目的根目录下,创建static/js文件夹。然后,在js文件夹下,创建一个名为main.js的新文件。static/js/main.js:我们完成了以下步骤://找到输出元素constoutput=document.getElementById("output");//初始化codemirror并传递配置以支持Python和dracula主题consteditor=CodeMirror.fromTextArea(document.getElementById("code"),{mode:{name:"python",version:3,singleLineStringErrors:false,},主题:“吸血鬼”,lineNumbers:真,indentUnit:4,匹配括号:真,});//设置编辑器的初始值editor.setValue("print('Helloworld')");output.value="正在初始化...\n";//将pyodide返回值添加到输出函数addToOutput(stdout){output.value+=">>>"+"\n"+stdout+"\n";}//清理输出部分functionclearHistory(){output.value="";}//初始化pyodide并在加载成功时显示sys.versionasyncfunctionmain(){letpyodide=awaitloadPyodide({indexURL:"https://cdn.jsdelivr.net/pyodide/v0.20.0/full/",});output.value=pyodide.runPython(`importsyssys.version`);output.value+="\n"+"Python就绪!"+"\n";返回pyodide;}//运行主函数letpyodideReadyPromise=main();//将编辑器值传递给pyodide.runPython函数并在输出部分显示结果asyncfunctionevaluatePython(){letpyodide=awaitpyodideReadyPromise;尝试{pyodide.runPython(`importiosys.stdout=io.StringIO()`);让result=pyodide.runPython(editor.getValue());让stdout=pyodide.runPython("sys.stdout.getvalue()");添加到输出(标准输出);}catch(err){addToOutput(err);}}1。初始化Code??Mirror,支持Python和Dracula主题2.初始化Pyodide。3.添加了一个名为evaluatePython的函数,当用户单击运行按钮时执行该函数。它将代码元素的值传递给pyodide.runPython,并通过addToOutput在输出元素中显示结果。4.新增clearHistory函数,当用户点击ClearHistory按钮时,会清空输出元素。要在本地运行Flask开发服务器,请运行:(env)$flaskrun现在服务器应该在端口5000上运行。在浏览器中导航到http://127.0.0.1:5000并测试代码编辑器。总结在本教程中,我们主要介绍了如何使用WebAssembly在浏览器中运行Python代码,但总的来说,WebAssembly涵盖了更广泛的用例。我们的部署平台比以往任何时候都更加多样化。WebAssembly可以影响客户端Web开发、服务器端开发、游戏、教育、云计算、移动平台、物联网、无服务器等。