Python Tech

PyScript(alpha版)代码演示

PyConUS2022公布的PyScript可以在浏览器执行Python代码,依赖于pyodide(WebAssembly的CPython)。相比pyodide更接近Web的开发体验。公布的 alpha 版本输出 Python 版本信息是: 3.10.2 (main, Apr 9 2022, 20:52:01) [Clang 14.0.0 (https://github.com/llvm/llvm-project 78e87970af888bbbd5652c31f3a8

下载项目源码,执行 npm run dev 运行的官方 demo 主要针对数据处理和 REPL,本文整理 Web 开发常见的几个代码片段:获取数据,读取本地数据库,事件绑定。

Install

只需要增加HTML标签引入文件:


<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>

但会从 cdn.jsdelivr.net 请求 pyodide.asm 相关文件。去年年底开始国内的jsdelivr访问时断时续,整个依赖有22MB,需要先设置好网络。

Usage

在HTML中使用<py-script>标签嵌入Python代码。和<script>标签一样,支持 src 属性直接引入 .py 文件。以Web开发很常用的两个场景,网络请求和访问数据库为例:

网络请求

这一版的pyscript还不能直接用Python库发起Web请求,如果调用 http.client 会报错:

  File "/lib/python3.10/http/client.py", line 941, in connect
    self.sock = self._create_connection(
  File "/lib/python3.10/socket.py", line 845, in create_connection
    raise err
  File "/lib/python3.10/socket.py", line 833, in create_connection
    sock.connect(sa)
BlockingIOError: [Errno 26] Operation in progress

即使用 asyncio 处理,也默认是浏览器发起 WebSocket 连接。

可以调用 pyodide.http.open_url 或使用 Javascript 的 fetch 从接口获取数据并在页面显示的代码:

 
<table class="table">
  <thead>
    <tr>
      <th>Key</th>
      <th>Value</th>
    </tr>
  </thead>
  <tbody id="table-data-rows">
  <tbody>
</table>

    <py-script>
import asyncio
from pyodide.http import open_url
import json

from js import fetch, document #调用Javascript的 fetch方法和document

async def request_github_api():
    url = "https://api.github.com/"
    r = await fetch(url)
    data = await r.json()
    # data = json.loads(open_url(url).read()) # open_url 读取数据,json处理成 dict

    rows = document.getElementById("table-data-rows") # 循环体的处理都是 Javascript 语法
    for k, v in data.object_entries():
    # for k, v in data.items(): # open_url 返回的 dict
        tr = document.createElement('tr') 
        key_td, value_td = document.createElement('td'), document.createElement('td')
        key_td.innerHTML = k
        value_td.innerHTML = v
        tr.append(key_td, value_td)
        rows.appendChild(tr)
asyncio.ensure_future(request_github_api())


    </py-script>

访问数据库

pyodide支持的 Python 包列表: https://github.com/pyodide/pyodide/tree/main/packages

已经支持 Sqlalchemy 这个主要的 ORM 包。因为缺少依赖且浏览器有限制,还不能连接远程数据库,但可以使用 Sqlite 的 inmemory 模式,代码如下:


    <py-env>
      - sqlalchemy # 其他包使用 <py-env> 引入
    </py-env>
    <py-script>
from sqlalchemy import create_engine, text

engine = create_engine("sqlite+pysqlite:///:memory:", future=True) # Sqlite 连接
with engine.connect() as conn:
    conn.execute(text("CREATE TABLE sites (name string, domain string)")) # 建表,写数据,提交
    conn.execute(
            text("INSERT INTO sites (name, domain) VALUES (:name, :domain)"),
            [{"name": "Dmyz1", "domain": "http://dmyz.org"}, {"name": "Dmyz2", "domain": "http://dmyz.net"}],
        )
    conn.commit()

    result = conn.execute(text("SELECT * FROM sites"))
    for row in result.all(): # 遍历结果。之前已经写过 DOM 的处理,这里直接 print
        print("Site: {}, Domain: {}".format(row[0], row[1]))

    </py-script>

事件绑定

PyScript 使用 pys-{EVENT} 属性在 HTML 标签上绑定事件,例如点击按钮获取时间戳:


<button id="time-btn" pys-onClick="get_time">Time</button>
<p id="current-time"></p>
<py-script>
import time
def get_time(*args, **kwargs):
    Element("current-time").write(time.time())
</py-script>

Afterwords

WebAssembly也发展近十年了,“让浏览器运行C/C++代码”听起来如同 nodejs 一样的新颖,然而只有一些简单的游戏演示,在 Web 应用方面让人眼前一亮的项目并不多。前几年接触iodide和pyodide的时候,也只觉得和 Jupyterhub 比较像,没想到合适的用途。

这次再看到 PyScript ,似乎只是 pyodide 加了几个 HTML 标签,但用起来顺手很多。第一印象是 PHP/JSP 曾经的混合写法,实际上手就发现它已经推进了 WebAssembly 的目标:让 C(Python)/C++ 成为真正能直接被浏览器解析,简单易上手的语言。虽然受限于网速、浏览器性能等因素,还替代不了 Javascript,但对于一些特定领域尤其是 Python 擅长的数据处理/机器学习,PyScript 应该能从 Javascript 分走一些。而且 Python 工程师们,以后就是名副其实的 Web 全栈了。

4 6 投票数
文章评分
订阅评论
提醒
guest

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

0 评论
内联反馈
查看所有评论