背景
长期以来,JavaScript一直是前端开发的主导语言,因为它能够在浏览器中原生运行,并通过DOM API与HTML和CSS交互。随着WebAssembly的出现,情况开始慢慢改变。Go、Rust、C、C++等语言现在可以以接近原生的速度在浏览器中运行,而Python也没有被落下。
随着Anaconda在2022年4月发布了PyScript,前端开发者现在可以用Python构建丰富的前端。此外,他们还可以利用Python生态系统,其中有一些有用的科学模块,如NumPy、Matplotlib和其他许多模块。
官方表示,通过使用PyScript,Python开发者便不需要担心程序部署问题,因为PyScript让程序直接在网页浏览器中运行,也就是说,可以在HTML文件中,分享开发成果,只要其他人在网页浏览器中打开文件,该文件中的程序代码就会开始运行。
What is PyScript
PyScript is a framework that allows users to run Python and create rich applications in the browser by simply using special HTML tags provided by the framework itself
-- 在浏览器运行python脚本和创建丰富应用的框架
核心功能:
- 浏览器支持运行Py
- 生态系统支持:可以运行主流的Python类库和科学技术工具包(比如:numpy, pandas, scikit-learn 等等)
- 互操作性:Python 和JavaScript对象双向通信,共享命名空间。
- 环境配置化:允许用户在页面代码运行时,自定义引入哪些包和文件。
- 框架灵活性:用户可方便使用现成的 UI 组件,如按钮、容器、文本框等等。
- 可灵活扩展框架:PyScript 是一个灵活的框架,开发人员可以在此基础上轻松地直接在 Python 中创建可扩展的组件。
How to use PyScript?
建议:禁用自动格式化工具,如Prettier
通常,前端开发人员在他们的文本编辑器中使用自动格式化工具(如Prettier)来在保存时格式化代码。虽然这对HTML、CSS和JavaScript很有效,但在Python代码中会引起问题,因为Python对缩进很严格。
目前,像Prettier这样的自动格式化工具不能识别PyScript的语法,这些工具将Python代码自动格式化为JavaScript,这就破坏了代码的缩进。为了补救这个问题,建议暂时禁用这个目录的自动格式化功能。
{
"editor.formatOnSave": false
}
引入PyScript
1、cdn
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
pyscript.css: 其中包含 PyScript 视觉组件、REPL、PyScript 载入器等的样式
pyscript.js: 该文件设置了使用PyScript的必要功能,比如创建像<py-script>
这样的标签,可以在该标签下写python代码
2、download it
使用PyScript
一旦我们引入了PyScript后,我们有两种方式在html中使用它
-
内部PyScript
- 可以放在head or body,取决于我们什么时候想让它执行
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Hello World!</title> <!-- linking to PyScript assets --> <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" /> <script defer src="https://pyscript.net/alpha/pyscript.js"></script> </head> <body> <!-- Put Python code inside the the <py-script> tag --> <py-script>print("Hello World!")</py-script> </body> </html>
-
外部PyScript
- 建议这么做
-
- 该文件可以被浏览器缓存,从而带来更快的性能
- 多个页面引用,减少重复代码
- Python代码可以用black或Python linters等工具进行格式化。这些工具目前对嵌入 HTML 文件的 Python 代码不起作用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Greetings!</title>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
// add the following line
<py-script src="./main.py"></py-script>
</body>
</html>
py-repl
The <py-repl>
element provides a REPL(Read Eval Print Loop) to evaluate multi-line Python and display output.
Examples
# 1
<py-repl auto-generate="true"> </py-repl>
# 2
<div id="replOutput"></div>
<py-repl output="replOutput">
hello = "Hello world!"
hello
</py-repl>
py-terminal
This is one of the core plugins in PyScript, which is active by default. With it, you can print to stdout
and stderr
from your python code, and the output will be displayed on the page in <py-terminal>
.
-- py打印的结果输出在terminal中
py-config
Use the <py-config>
tag to set and configure general metadata along with declaring dependencies for your PyScript application. The configuration has to be set in either TOML(default) or JSON format.
# toml
<py-config>
[splashscreen]
autoclose = true
[[runtimes]]
src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js"
name = "pyodide-0.21.2"
lang = "python"
</py-config>
#json
<py-config type="json">
{
"splashscreen": { // 关闭加载画面
"autoclose": true
},
"runtimes": [{
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
"name": "pyodide-0.21.2",
"lang": "python"
}]
}
</py-config>
py-env
这个标签用于声明所需的依赖项
<py-env>
- numpy
- requests
- paths
- /data/road.png
</py-env>
<py-script>
import numpy as np
import requests
</py-script>
PyScript操作html元素
PyScript提供了Element
类,它允许你使用其ID来选择一个HTML元素。
<input id="my-input" value="hello world"></input>
// Properties:innerHtml、element、id、value
// Methods:write、clear、select、clone、remove_class、add_class
<py-script>
from pyscript import Element
my_input = Element('my-input')
print(my_input.value) # prints 'hello world'
</py-script>
PyScript中操作JavaScript
PyScript提供了一个js
模块,让你可以访问JavaScript方法,如querySelector()
,createElement()
,appendChild()
等,以访问和操作HTML元素。
import js
print(js.window.innerHeight)
nav = js.document.createElement("div")
js.document.body.prepend(nav)
js.console.log("nav element created")
js.localStorage.setItem("comment", text)
Pyscript是怎么工作的
PyScript建立在Pyodide之上,它将CPython移植到WebAssembly。WebAssembly是一种低级别的二进制格式,允许你用其他语言编写程序,然后在浏览器中执行。有了WebAssembly中的CPython,我们可以在浏览器中安装和运行Python包,而PyScript则抽象了大部分Pyodide操作,可以专注于在浏览器中用Python构建前端应用程序。
Pyodide 带有一个强大的 Javascript ⟺ Python 外部函数接口.Pyodide 可以将Python编译成WebAssembly。
从loadRuntime方法中也可以发现,运行前会加载 Pyodide 模块,程序耗时也主要来自这块(严重依赖 pyodide 模块加载速度,官方CDN不太稳定)
执行代码主要也是借助pyodide的runPython方法
因此,Pyscript相当于封装了一层Pyodide实现
pyodide.runPython(`
// python code
`);
问题
PyScript 开创式地提供了前端使用Python处理复杂数据的模式,但加载方式和渲染模式还是存在较大改良空间。(因为要加载Pyodide,且强依赖Pyodide的cdn,因此其实会有很明显的延迟)
并且目前PyScript似乎还没法支持一些 机器学习 or cv库的能力
Such as:
我们使用PyScript去运行这段代码时 里面使用到了 tensorflow
<py-env>
- numpy
- tensorflow
- nltk
</py-env>
<body>
<py-script>
import random
import json
import pickle
import numpy as np
import nltk
from nltk.stem import WordNetLemmatizer
intents = json.loads(open("./intents.json").read())
import tensorflow as tf
keras = tf.keras
from keras.models import load_model
//further code..
</py-script>
就会发现 console报错
仔细在网上查阅原因发现
So 其实目前PyScript只能支持 “pure Python”在浏览器跑,而一些机器学习、cv的一些库其实常常是含有其他语言的component的,并不能在pyScript中引用,因此个人认为目前做一些科学计算的用途会更多一些