由Anaconda创建的PyScript是一项实验性的但很有前途的新技术,它使Python运转时在支撑WebAssembly的浏览器中作为一种脚本言语运用。

每个现代常用的浏览器现在都支撑WebAssembly,这是许多言语(如C、C++和Rust)能够编译的高速运转时规范。Python的参考实现是用C言语编写的,一个早期项目Pyodide供给了Python运转时的WebAssembly移植。

不过,PyScript的方针是供给一个完好的浏览器环境,将Python作为一种网络脚本言语运转。它建立在Pyodide之上,但增加或加强了一些功用,如从规范库中导入模块、运用第三方导入、装备与文档目标模型(DOM)的双向交互,以及做许多其他在Python和JavaScript国际中有用的事情。

现在,PyScript仍然是一个原型和实验性项目。Anaconda 并不推荐在生产中运用它。但猎奇的用户能够在PyScript网站上测验一些比方,并运用可用的组件在浏览器中构建实验性的Python+JavaScript应用程序。

在这篇文章中,咱们将参观一下PyScript的基础知识,看看它是怎么让Python和JavaScript进行交互的。

运用PyScript编程

PyScript的中心是一个单一的JavaScript include,你能够将其增加到网页中。这个 include 加载了根本的 PyScript 运转时刻,并主动增加了对 PyScript 中运用的自定义标签的支撑。

下面是一个PyScript的 “hello, world “项目的简单比方:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/unstable/pyscript.js"></script>
    </head>
    <body>
<py-script output="out">
print("Hello world")
</py-script>
<div id="out"></div>
    </body>
</html>

head 文档中的script 标签加载了PyScript的中心功用。pyscript.css 样式表是可选的,但很有用。在其他方面,它在页面加载时向用户插入了关于页面正在做什么的告诉–加载Python运转时,初始化,等等。

Python代码被包含在自定义的py-script 标签中。请留意,代码应该按照Python的缩进常规进行格式化,否则将无法正常运转。假如你运用的编辑器能主动重新格式化HTML,请留意这一点;它可能会弄乱py-script 块的内容,使其无法运转。

一旦PyScript组件加载完毕,任何Python代码都会被评估。假如标签中的脚本写到stdout (如print) 语句中,你能够通过供给一个output 属性来指示在页面的什么地方显示输出。在这个比方中,脚本的stdout 被引导到ID为"out"div

假如你把它保存到一个文件中,并在网络浏览器中打开它,你会首先看到一个 “加载 “指示器和一个暂停,由于浏览器获得了PyScript的运转时刻并将其设置好。该运转时在未来的加载中应坚持缓存,但仍需要一些时刻来激活。之后,Hello world 应该出现在页面上。

规范库导入

仅仅运用Python的内建程序的脚本只要一点用处。Python 的规范库在 PyScript 中可用,就像你在常规 Python 中运用它一样:只需import 并开始作业。规范库的导入在PyScript中应该仅仅作业。

假如你想修改上面的脚本块来显示当前的时刻,你不需要用与传统Python不同的方法:


import datetime
print ("Current date and time:",    datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S"))

运用来自PyPI的库

假如咱们想从PyPI中装置一个包并运用它呢?PyScript 有另一个标签,py-env ,它指定了需要装置的第三方软件包。让咱们用这两个块来替换原始脚本中的py-script 块:

<py-env>
- humanize
</py-env>
<py-script output="out">
from datetime import datetime
import humanize
now_int = int(datetime.timestamp(datetime.now()))
now_fmt = humanize.intcomma(now_int)
print("It has been", now_fmt, "seconds since the epoch.")
</py-script>

py-env 块让咱们列出要增加的软件包,就像咱们在 Python 项目的requirements.txt 文件中列出它们一样。然后咱们能够像对待其他 Python 软件包一样导入和运用它们。在这个比方中,咱们运用了一个名为humanize 的第三方软件包,以使数字输出更容易阅读。

留意,并不是一切来自PyPI的包都能按预期装置和运转。例如,requests 需要拜访尚不支撑的网络组件。(这个问题的一个可能的解决方法是运用pyodide.http.pyfetch ,它被原生支撑)。可是纯 Python 包,如humanize ,应该运转杰出。Anaconda 供给的比方中运用的包,如numpy,pandas,bokeh, 或matplotlib ,也能够运转。

本地导入

对于另一种常见的情况,假定你想从与你的网页在同一目录树下的其它 Python 脚本中导入。运用导入能够更容易地将更多的 Python 逻辑从网页自身移出,在那里它和你的演示文稿混在一同,可能会变得难以处理。

一般,Python 运用文件体系中其他.py 文件的存在作为它能够导入的指示。PyScript 不能以这种方法作业,所以你需要指定哪些文件能够作为可导入模块。

比方说,你有一个名为index.html 的网页,在你的 web 服务器的某个目录下,你想在它旁边放置一个名为main.py 的 Python 文件。这样,你的页内脚本就能够仅仅import main ,而你能够把大部分的 Python 逻辑限制在实践的.py 文件中。

在你的py-env 块中指定你想导入的 Python 文件。

- paths:`` - ./main.py

这将允许main.py ,在与网页自身相同的 web 服务器目录下,能够与import main 一同导入。

要记住一件重要的事情。你不能对你在浏览器中本地发动的网页进行这样的导入。这是由于WebAssembly运转时和浏览器自身对文件体系拜访的限制造成的。相反,你需要在网络服务器上托管这些网页,以供给网页和.py 文件。

REPL 标签

Python用户应该了解Jupyter Notebook,它是Python的浏览器内实时编码环境,一般用于数学和统计学。PyScript为这样的环境供给了一个原始的构建模块,即py-repl 标签。

py-repl 在网页上生成一个输入字段,其功用就像一个十分根本的Jupyter笔记本环境。下面是一个来自Anaconda自己演示的比方:

<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
  </head>
  <body>
    <h1><b>pyscript REPL</b></h1>
    Tip: press Shift-ENTER to evaluate a cell
    <br>
    <div>
      <py-repl id="my-repl" auto-generate="true"> </py-repl>
    </div>
  </body>
</html>

运转这段代码,你会看到一个输入字段,它的作业原理相似于Python的REPL。

目前,REPL标签很少有记录的自定义方法。例如,假如你想以编程方法拜访一个单元格的内容或其结果,没有清晰的文档说明怎么做到这一点。

PyScript 介绍——在你的网络浏览器中运行Python
PyScript的相似Jupyter的REPL组件能够让你在页面中交互式地运转Python,尽管它还不是很灵活或可装备。

与 JavaScript 事情监听器互动

由于 PyScript 是根据pyodide 的,所以它运用pyodide 的机制来与 DOM 交互。例如,假如咱们想获得一个网页上的输入框的值并在咱们的Python代码中运用它,咱们会这样做。

<input id="txt">
<py-script>
from js import document, console
from pyodide import create_proxy
def _eventlog(e):
    console.log(f"Input value: {e.target.value}")
eventlog = create_proxy(_eventlog)
document.getElementById("txt").addEventListener("input", eventlog)
</py-script>

js 库为许多常见的 JavaScript 实体供给了一个 Python 接口,比方documentconsole 目标。它们在PyScript中的行为与在JavaScript中的行为简直完全相同。pyodide 中的create_proxy 函数能够让咱们取一个 Python 函数目标并为它生成一个 JavaScript 接口,因而它能够被用作input 框的事情监听器。input 框中的任何按键都会被记录到控制台,但它们也能够在Python端被处理。