Brython:浏览器中的 Python(1)

举报
Yuchuan 发表于 2021/12/07 16:54:03 2021/12/07
【摘要】 如果您是一名 Web 开发人员,更喜欢编写 Python 而不是 JavaScript,那么在浏览器中运行的 Python 实现Brython可能是一个有吸引力的选择。 JavaScript是前端 Web 开发的事实上的语言。复杂的 JavaScript 引擎是所有现代 Internet 浏览器的固有部分,自然会促使开发人员使用 JavaScript 编写前端 Web 应用程序。Brython通

目录

如果您是一名 Web 开发人员,更喜欢编写 Python 而不是 JavaScript,那么在浏览器中运行的 Python 实现Brython可能是一个有吸引力的选择。

JavaScript前端 Web 开发的事实上的语言。复杂的 JavaScript 引擎是所有现代 Internet 浏览器的固有部分,自然会促使开发人员使用 JavaScript 编写前端 Web 应用程序。Brython通过使 Python 成为浏览器中的一流公民语言以及访问浏览器中可用的所有现有 JavaScript 库和 API,提供了两全其美的优势。

在本教程中,您将学习如何:

  • 在本地环境中安装 Brython
  • 在浏览器中使用Python
  • 编写与 JavaScript 交互的Python 代码
  • 使用您的 Web 应用程序部署Python
  • 使用 Python创建浏览器扩展
  • 将 Brython 与其他用于 Web 应用程序的Python 实现进行比较

作为熟悉Web 开发的中级 Python 开发人员,如果您还具备一些HTML和 JavaScript知识,您将从本教程中获得最大收益。对于 JavaScript 复习,请查看Python 与 JavaScript for Pythonistas

在浏览器中运行 Python:好处

尽管 JavaScript 是前端 Web 开发中无处不在的语言,但以下几点可能适用于您:

  • 您可能不喜欢用 JavaScript 编写代码。
  • 您可能希望利用您的 Python 技能。
  • 您可能不想花时间学习 JavaScript 来探索浏览器技术。
  • 您可能不喜欢被迫学习和使用 JavaScript 来实现 Web 应用程序。

不管是什么原因,许多开发人员更喜欢基于 Python 的替代 JavaScript 来利用浏览器的强大功能。

在浏览器中运行 Python 有几个好处。它允许您:

  • 在服务器和浏览器中执行相同的 Python 代码
  • 使用 Python处理各种浏览器 API
  • 使用 Python 操作文档对象模型 (DOM)
  • 使用 Python 与 Vue.js 和 jQuery 等现有 JavaScript 库进行交互
  • 使用 Brython 编辑器向 Python 学生教授 Python 语言
  • 在用 Python 编程时保持乐趣感

与 JavaScript 中的相同代码相比,在浏览器中使用 Python 的一个副作用是性能损失。然而,这个缺点并没有超过上面概述的任何好处。

实现同构 Web 开发

同构 JavaScript通用 JavaScript强调 JavaScript 应用程序应该在客户端和服务器上运行。这是假设后端是基于 JavaScript 的,即Node服务器。使用FlaskDjango 的Python 开发人员也可以将同构原理应用于 Python,前提是他们可以在浏览器中运行 Python。

Brython 允许您使用 Python 构建前端并在客户端和服务器之间共享模块。例如,您可以共享验证功能,例如以下用于规范化和验证美国电话号码的代码:

 1import re
 2
 3def normalize_us_phone(phone: str) -> str:
 4    """Extract numbers and digits from a given phone number"""
 5    return re.sub(r"[^\da-zA-z]", "", phone)
 6
 7def is_valid_us_phone(phone: str) -> bool:
 8    """Validate 10-digit phone number"""
 9    normalized_number = normalize_us_phone(phone)
10    return re.match(r"^\d{10}$", normalized_number) is not None

normalize_us_phone()消除任何非字母数字字符,而如果输入字符串正好包含十位数字且没有字母字符,则is_valid_us_phone()返回True。可以在 Python 服务器上运行的进程和使用 Brython 构建的客户端之间共享相同的代码。

访问 Web API

Internet 浏览器向 JavaScript公开标准化的Web API。这些标准是HTML Living Standard 的一部分。一些 Web API 示例包括:

Brython 允许您使用 Web API 并与 JavaScript 交互。您将在后面的部分中使用一些 Web API 。

原型设计和 JavaScript 库

Python 通常用于为代码片段、语言结构或更大的想法制作原型。使用 Brython,您可以在浏览器中使用这种常见的编码实践。例如,您可以使用Brython 控制台或交互式编辑器来试验一段代码。

打开在线编辑器并输入以下代码:

 1from browser import ajax
 2
 3def on_complete(req):
 4    print(req.text)
 5
 6language = "fr"
 7
 8ajax.get(f"https://fourtonfish.com/hellosalut/?lang={language}",
 9         blocking=True,
10         oncomplete=on_complete)

下面是这段代码的工作原理:

  • 1个线 进口ajax模块。
  • 第 3 行定义了从 获得响应后调用on_complete()回调函数ajax.get()
  • 第 6 行调用ajax.get()使用HelloSalut API检索法语“hello”的翻译。请注意,blocking可以TrueFalse当您在 Brython 编辑器中执行此代码时。它需要True你在Brython控制台执行相同的代码。

单击输出窗格上方的运行以查看以下结果:

{"code":"fr","hello":"Salut"}
<completed in   5.00 ms>

尝试将语言从frto修改es并观察结果。此 API 支持的语言代码在HelloSalut 文档中列出。

注意:HelloSalut 是 Internet 上可用的公共 API 之一,并列在公共 API GitHub 项目中

您可以在在线编辑器中修改代码片段以使用不同的公共 API。例如,尝试从Public APIs 项目中获取一个随机公共 API

 1from browser import ajax
 2
 3def on_complete(req):
 4    print(req.text)
 5
 6ajax.get("https://api.publicapis.org/random",
 7         blocking=True,
 8         oncomplete=on_complete)

将上面的代码复制到在线 Brython 编辑器中,然后单击运行以显示结果。以下是 JSON 格式的示例:

{
  "count": 1,
  "entries": [
    {
      "API": "Open Government, USA",
      "Description": "United States Government Open Data",
      "Auth": "",
      "HTTPS": true,
      "Cors": "unknown",
      "Link": "https://www.data.gov/",
      "Category": "Government"
    }
  ]
}

由于端点获取随机项目,您可能会得到不同的结果。有关 JSON 格式的更多信息,请查看在 Python 中使用 JSON 数据

您可以像在Python 解释器中一样使用原型设计来尝试常规 Python 代码。因为您处于浏览器的上下文中,所以 Brython 还提供了以下方法:

作为一种快捷方式,您可以通过打开 Brython 网站上提供的控制台或编辑器来利用上述大多数功能。这不需要您在本地计算机上安装或运行任何东西。相反,它为您提供了一个与 Python 和 Web 技术交互的在线游乐场。

向学生教授 Python

Brython 既是一个 Python 编译器,也是一个用 JavaScript 编写的解释器。因此,您可以在浏览器中编译和运行 Python 代码。Brython 网站上提供的在线编辑器演示了此功能的一个很好的示例。

使用在线编辑器,Python 在浏览器中运行。无需在机器上安装Python,也无需将代码发送到服务器执行。反馈对用户来说是即时的,这种方法不会将后端暴露给恶意脚本。学生可以在任何带有浏览器的设备上试验 Python,例如手机或 Chromebook,即使互联网连接不稳定。

考虑性能

Brython 站点指出,该实现的执行速度与 CPython 相当。但是 Brython 是在浏览器中执行的,这个环境中的引用是 JavaScript 烘焙到浏览器引擎中的。因此,预计 Brython 会比手写的、经过良好调整的 JavaScript 慢。

Brython 将 Python 代码编译成 JavaScript,然后执行生成的代码。这些步骤会对整体性能产生影响,并且 Brython 可能并不总能满足您的性能要求。在某些情况下,您可能需要将某些代码执行委托给 JavaScript 甚至WebAssembly。您将在有关WebAssembly的部分中看到如何构建 WebAssembly 以及如何在 Python 中使用生成的代码。

但是,不要让感知性能影响您使用 Brython。例如,导入 Python 模块可能会导致从服务器下载相应的模块。为了说明这种情况,打开 Brython 控制台并执行以下代码:

>>>
>>> import uuid

显示提示之前的延迟(在测试机器上为 390 毫秒)是显而易见的。这是因为 Brython 必须下载uuid及其依赖项,然后编译下载的资源。但是,从那时起,执行uuid. 例如,您可以使用以下代码生成一个随机的通用唯一标识符,UUID 版本 4:

>>>
>>> uuid.uuid4()
UUID('291930f9-0c79-4c24-85fd-f76f2ada0b2a')

调用uuid.uuid4()生成一个UUID对象,其字符串表示形式打印在控制台中。调用uuid.uuid4()立即返回并且比uuid模块的初始导入快得多。

Having Fun

如果您正在阅读本教程,那么您可能对在浏览器中编写 Python 代码感兴趣。看到在浏览器中执行的 Python 代码对大多数 Pythonistas 来说都是令人兴奋的,并唤醒了一种乐趣和无限的可能性。

Brython 的作者Pierre Quentel和该项目的贡献者在承担使 Python 与 Web 浏览器兼容的艰巨任务的同时,也牢记 Python 的乐趣。

为了证明这一点,将浏览器指向 Brython 交互式控制台,然后在 Python 提示符下键入以下内容:

import this

与在本地机器上使用 Python 的体验类似,Brython 会即时编译和执行指令并打印Python 之禅。它发生在浏览器中,并且 Python 代码执行不需要与后端服务器进行任何交互:

布莱顿控制台

您还可以在相同的浏览器环境中使用以下代码尝试另一个经典的 Python复活节彩蛋

import antigravity

Brython 包含您在 Python 参考实现中会发现的相同幽默点

现在您已经熟悉了使用 Brython 的基础知识,您将在以下部分探索更高级的功能。

安装 Brython

试用 Brython 的在线控制台是一个好的开始,但它不允许您部署 Python 代码。在本地环境中安装 Brython 有几种不同的选择:

下面概述了每种方法的说明,但如果您已经做出决定,可以直接跳到您喜欢的方法。

CDN安装

一个内容分发网络(CDN)是服务器的网络,它允许以提高性能和下载速度为在线内容。您可以从几个不同的 CDN 安装 Brython 库:

如果您想部署静态网站并以最小的开销向您的页面添加一些动态行为,您可以选择此安装。除了使用 Python 而不是 JavaScript 之外,您可以将此选项视为jQuery的替代品。

为了说明 Brython 与 CDN 的使用,您将使用 CDNJS。使用以下 HTML 代码创建一个文件:

 1<!doctype html>
 2<html>
 3    <head>
 4        <script
 5          src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.js">
 6        </script>
 7    </head>
 8    <body onload="brython()">
 9        <script type="text/python">
10            import browser
11            browser.alert("Hello Real Python!")
12        </script>
13    </body>
14</html>

以下是此 HTML 页面的关键元素:

  • 第 5 行brython.js从 CDNJS加载。

  • 第8个执行brython()时,文档完成加载brython()读取当前作用域中的 Python 代码并将其编译为 JavaScript。有关更多详细信息,请参阅了解 Brython 的工作原理部分。

  • 第 9行将脚本的类型设置为text/python. 这向 Brython 指示需要编译和执行哪些代码。

  • 第 10 行导入browser了一个 Brython 模块,它公开允许与浏览器交互的对象和函数。

  • 第 11 行调用alert(),它显示一个带有文本的消息框"Hello Real Python!"

将文件另存为index.html,然后双击该文件以使用默认 Internet 浏览器打开它。浏览器显示一个消息框,"Hello Real Python!"单击OK关闭消息框:

Brython 中的警报框

要减小下载文件的大小,尤其是在生产中,请考虑使用以下文件的最小化版本brython.js

 1<script
 2  src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js">
 3</script>

从用户的角度来看,最小化版本将减少下载时间和感知延迟。在了解 Brython 的工作原理中,您将了解浏览器如何加载 Brython 以及如何执行上述 Python 代码。

GitHub 安装

GitHub 安装与 CDN 安装非常相似,但它允许您使用最新的开发版本来实现 Brython 应用程序。您可以复制前面的示例并修改head元素中的 URL以获得以下内容index.html

<!doctype html>
<html>
  <head>
    <script
      src="https://raw.githack.com/brython-dev/brython/master/www/src/brython.js">
    </script>
  </head>
  <body onload="brython()">
    <script type="text/python">
      import browser
      browser.alert("Hello Real Python!")
    </script>
  </body>
</html>

将此文件保存在本地目录中后,双击index.html以在浏览器中呈现您通过 CDN 安装获得的相同页面。

PyPI 安装

到目前为止,您不需要在本地环境中安装任何东西。相反,您已在 HTML 文件中指明浏览器可以在何处找到 Brython 包。当浏览器打开页面时,它会从适当的环境(CDN 或 GitHub)下载 Brython JavaScript 文件。

Brython 也可用于在PyPI上进行本地安装。PyPI 安装适合您,如果:

  • 您需要对 Brython 环境进行更多控制和自定义,这超出了指向 CDN 文件时可用的范围。
  • 您的背景是 Python 并且您熟悉pip.
  • 您需要本地安装以最大限度地减少开发过程中的网络延迟。
  • 您希望以更精细的方式管理您的项目和可交付成果。

从 PyPI installs 安装 Brython brython_cli,这是一个命令行工具,可用于自动生成项目模板或打包和捆绑模块等功能,以简化 Brython 项目的部署。

有关更多详细信息,您可以查阅本地安装文档以查看brython-cli安装后环境中可用的功能。brython-cli仅适用于此类安装。如果您从CDN或使用npm安装,则它不可用。您将brython-cli在本教程后面看到实际操作。

在安装 Brython 之前,您要为这个项目创建一个Python 虚拟环境

在 Linux 或 macOS 上,执行以下命令:

$ python3 -m venv .venv --prompt brython
$ source .venv/bin/activate
(brython) $ python -m pip install --upgrade pip
Collecting pip
  Downloading pip-20.2.4-py2.py3-none-any.whl (1.5 MB)
     |████████████████████████████████| 1.5 MB 1.3 MB/s
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 20.2.3
    Uninstalling pip-20.2.3:
      Successfully uninstalled pip-20.2.3

在 Windows 上,您可以执行以下操作:

> python3 -m venv .venv --prompt brython
> .venv\Scripts\activate
(brython) > python -m pip install --upgrade pip
Collecting pip
  Downloading pip-20.2.4-py2.py3-none-any.whl (1.5 MB)
     |████████████████████████████████| 1.5 MB 1.3 MB/s
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 20.2.3
    Uninstalling pip-20.2.3:
      Successfully uninstalled pip-20.2.3

您刚刚为您的项目创建了一个专用的 Python 环境并更新pip了最新版本。

在接下来的步骤中,您将安装 Brython 并创建一个默认项目。这些命令在 Linux、macOS 和 Windows 上是相同的:

(brython) $ python -m pip install brython
Collecting brython
  Downloading brython-3.9.0.tar.gz (1.2 MB)
     |████████████████████████████████| 1.2 MB 1.4 MB/s
Using legacy 'setup.py install' for brython, since package 'wheel'
is not installed.
Installing collected packages: brython
    Running setup.py install for brython ... done
(brython) $ mkdir web
(brython) $ cd web
(brython) $ brython-cli --install
Installing Brython 3.9.0
done

您已经从 PyPI 安装了 Brython,创建了一个名为 的空文件夹web,并通过brython-cli在安装期间在您的虚拟环境中执行复制来生成默认项目框架。

web文件夹中,brython-cli --install创建了一个项目模板并生成了以下文件:

文件 描述
README.txt 关于如何运行 Python HTTP 服务器并打开的文档 demo.html
brython.js 核心 Brython 引擎(编译器、运行时和浏览器界面)
brython_stdlib.js Brython 标准库
demo.html Brython 演示 HTML 页面的源代码
index.html 可用作项目起始页的基本示例
unicode.txt 使用的 Unicode 字符数据库 (UCD) unicodedata

要测试这个新创建的 Web 项目,您可以使用以下命令启动本地 Python Web 服务器:

(brython) $ python -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

执行 时python -m http.server,Python 在端口 8000 上启动 Web 服务器。预期的默认页面是index.html。将您的互联网浏览器指向http://localhost:8000以显示带有文本的页面Hello

布莱顿指数

对于更完整的示例,您可以将浏览器地址栏中的URL更改为http://localhost:8000/demo.html。您应该会看到一个类似于 Brython 演示页面的页面:

布莱顿演示

通过这种方法,Brython JavaScript 文件直接从您的本地环境加载。注意元素中的src属性:headindex.html

 1<!doctype html>
 2<html>
 3  <head>
 4   <meta charset="utf-8">
 5   <script type="text/javascript" src="brython.js"></script>
 6   <script type="text/javascript" src="brython_stdlib.js"></script>
 7  </head>
 8  <body onload="brython(1)">
 9    <script type="text/python">
10      from browser import document
11      document <= "Hello"
12    </script>
13  </body>
14</html>

上面的 HTML 缩进以提高本教程的可读性。该命令brython_cli --install不会缩进它生成的初始 HTML 模板。

HTML 文件引入了一些新的 Brython 功能:

  • 第 6 行加载brython_stdlib.js了编译为 JavaScript 的 Python 标准库。

  • 第 8 行brython()使用参数调用以将1错误消息打印到浏览器控制台

  • 10个线进口document的模块browser。访问 DOM 的函数在document.

  • 第 11 行显示了<=作为语法糖添加到 Python中的新符号 ( ) 。在本例中,document <= "Hello"是 的替代品document.body.appendChild(document.createTextNode("Hello"))。有关这些 DOM 函数的详细信息,请查看Document.createTextNode

该运算符<=用于向 DOM 的元素添加子节点。您将在 Brython 中的 DOM API 中详细了解如何使用 Brython 特定的运算符。

安装

如果您精通 JavaScript 生态系统,那么npm 安装可能会吸引您。在执行此安装之前需要Node.jsnpm

使用 npm 安装将使 JavaScript Brython 模块像任何其他 JavaScript 模块一样在您的项目中可用。然后,您将能够利用您最喜欢的 JavaScript 工具来测试、打包和部署 Brython 解释器和库。如果您已经使用 npm 安装了现有的 JavaScript 库,则此安装是理想的。

注意:如果您的系统上没有安装 Node.js 和 npm,请考虑阅读本节的其余部分以获取信息,因为您可以安全地跳过安装本身。本教程的其余部分不依赖于任何示例的 npm 安装方法。

假设您的系统上安装了 npm,通过在一个空目录中调用来创建一个默认package.json文件npm init --yes

$ npm init --yes
Wrote to /Users/john/projects/brython/npm_install/package.json:

{
  "name": "npm_install",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

要将 Brython 集成到您的项目中,请执行以下命令:

$ npm install brython
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN npm_install@1.0.0 No description
npm WARN npm_install@1.0.0 No repository field.

+ brython@3.9.0
added 1 package from 1 contributor and audited 1 package in 1.778s
found 0 vulnerabilities

您可以忽略警告并注意 Brython 已添加到您的项目中。要确认,打开package.json并确保您有一个dependencies指向包含brython条目的对象的属性:

 1{
 2  "name": "npm_install",
 3  "version": "1.0.0",
 4  "description": "",
 5  "main": "index.js",
 6  "scripts": {
 7    "test": "echo \"Error: no test specified\" && exit 1"
 8  },
 9  "author": "",
10  "license": "ISC",
11  "dependencies": {
12    "brython": "^3.9.0"
13  }
14}

对于前面的示例,您可以创建以下内容index.html并使用浏览器打开它。此示例不需要 Web 服务器,因为浏览器能够在node_modules/brython/brython.js本地加载 JavaScript 文件:

 1<!doctype html>
 2<html>
 3<head>
 4  <meta charset="utf-8">
 5  <script
 6    type="text/javascript"
 7    src="node_modules/brython/brython.js" defer>
 8  </script>
 9</head>
10<body onload="brython()">
11<script type="text/python">
12from browser import document
13document <= "Hello"
14</script>
15</body>
16</html>

浏览器呈现index.html和负载brython.jsscriptURL中index.html。在本示例中,您看到了一种利用 JavaScript 生态系统安装 Brython 的不同方式。在本教程的其余部分,您将编写依赖于 CDN 安装或 PyPI 安装的代码。

Brython 安装选项回顾

Brython 一只脚涉足 Python 世界,另一只脚涉足 JavaScript。不同的安装选项说明了这种跨技术的情况。根据您的背景选择最吸引您的装置。

下表为您提供了一些指导:

安装类型 语境
CDN 您想要部署一个静态网站并以最小的开销向您的页面添加一些动态行为。您可以将此选项视为 jQuery 的替代品,但使用 Python 而不是 JavaScript。
GitHub 这类似于 CDN 安装,但您想尝试 Brython 的前沿版本。
PyPI 你的背景是 Python。您熟悉pip以及如何创建 Python 虚拟环境。您的项目可能需要一些您希望在本地环境或源代码存储库中维护的自定义设置。您希望对您将分发的软件包有更多的控制权。您希望在无法访问 Internet 的封闭环境中进行部署。
npm 您的背景是 JavaScript。您熟悉 JavaScript 工具,尤其是 Node.js 和 npm。您的项目可能需要一些您希望在本地环境或源代码存储库中维护的自定义设置。您希望对要分发的软件包有更多的控制权。您希望在无法访问 Internet 的封闭环境中进行部署。

下表总结了可供您使用的不同安装选项。在下一节中,您将详细了解 Brython 的工作原理。

了解 Brython 的工作原理

您对安装 Brython 的不同方法的浏览为您提供了一些有关实现如何工作的高级线索。以下是您迄今为止在本教程中发现的一些特征的摘要:

  • 它是 JavaScript 中的 Python 实现。
  • 它是一个 Python 到 JavaScript 的翻译器和一个在浏览器中执行的运行时。
  • 它公开了两个可用作 JavaScript 文件的主要库:
    1. brython.js是 Brython 语言的核心,详见Brython 核心组件
    2. brython_stdlib.jsBrython 标准库
  • 它调用brython(),它script使用text/python类型编译包含在标签中的 Python 代码。

在以下部分中,您将更详细地了解 Brython 的工作原理。

Brython 核心组件

Brython的核心包含在brython.js或在brython.min.js,所述发动机Brython的最小化版本。两者都包括以下关键组件:

  • brython()是 JavaScript 全局命名空间中公开的主要 JavaScript 函数。如果不调用此函数,您将无法执行任何 Python 代码。这是您必须显式调用的唯一 JavaScript 函数。

  • __BRYTHON__是一个 JavaScript 全局对象,它包含运行 Python 脚本所需的所有内部对象。当您编写 Brython 应用程序时,不会直接使用此对象。如果您查看 Brython 代码,包括 JavaScript 和 Python,那么您会看到__BRYTHON__. 您不需要使用此对象,但是当您看到错误或想要在浏览器控制台中调试代码时,您应该注意它。

  • 内置类型Python 内置类型在 JavaScript 中的实现。例如,py_int.jspy_string.jspy_dicts.js分别是intstr和 的实现dict

  • browser浏览器模块,它公开前端 Web 应用程序中常用的 JavaScript 对象,例如使用的 DOM 接口document和使用window对象的浏览器窗口。

当您完成本教程中的示例时,您将看到这些组件中的每一个都在运行。

Brython 标准库

现在您已经对核心 Brython 文件有了一个总体了解brython.js,您将了解它的配套文件brython_stdlib.js.

brython_stdlib.js公开 Python 标准库。生成此文件时,Brython 将 Python 标准库编译为 JavaScript 并将结果连接到 bundle 中brython_stdlib.js

Brython 旨在尽可能接近Python 参考实现CPython。有关 CPython 的更多信息,请查看您的 CPython 源代码CPython 内部指南指南

由于 Brython 在 Web 浏览器的上下文中运行,因此它有一些限制。例如,浏览器不允许直接访问文件系统,因此os.open()无法打开文件。与网络浏览器无关的功能可能无法实现。例如,下面的代码运行在 Brython 环境中:

>>>
>>> import os
>>> os.unlink()
Traceback (most recent call last):
  File <string>, line 1, in <module>
NotImplementedError: posix.unlink is not implemented

os.unlink()引发异常,因为从浏览器环境中删除本地文件是不安全的,并且文件和目录条目 API只是一个草案提案。

Brython 仅支持原生 Python 模块。它不支持用 C 构建的 Python 模块,除非它们已经用 JavaScript 重新实现。例如,在 CPython中用Chashlib编写并在 Brython 中用JavaScript实现。您可以查阅Brython 发行版中的模块列表以与 CPython 实现进行比较。

您需要包含brython_stdlib.jsbrython_stdlib.min.js从 Python 标准库导入模块。

Brython in Action

此时,您可能想知道 Brython 在只知道其 JavaScript 引擎的浏览器中的行为方式。重用前面的示例和浏览器中可用的工具,您将了解在浏览器中执行 Python 代码所涉及的过程。

CDN 服务器安装部分,您看到了以下示例:

 1<!doctype html>
 2<html>
 3    <head>
 4        <script
 5            src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.js">
 6        </script>
 7    </head>
 8    <body onload="brython()">
 9        <script type="text/python">
10            import browser
11            browser.alert("Hello Real Python!")
12        </script>
13    </body>
14</html>

加载和解析 HTML 页面后,brython()执行以下步骤:

  1. 读取包含在元素中的 Python 代码 <script type="text/python">
  2. 将 Python 代码编译为等效的 JavaScript
  3. 评估生成的 JavaScript 代码 eval()

在上面的示例中,Python 代码嵌入在 HTML 文件中:

<script type="text/python">
    import browser
    browser.alert("Hello Real Python!")
</script>

另一种选择是从单独的文件下载 Python 代码:

<head>
    <script src="https://www.example.com/main.py"
            type="text/python"></script>
</head>

在这种情况下,Python 文件将如下所示:

import browser
browser.alert("Hello Real Python!")

将 Python 代码与 HTML 代码分开是一种更简洁的方法,它允许您利用代码编辑器的优点和功能。大多数编辑器都支持 HTML 中的嵌入式 JavaScript,但它们不支持 HTML 中的内联 Python。

Brython 的内部结构

本节深入探讨了将 Python 代码转换为 JavaScript 的过程。如果您对这些细节不感兴趣,请随意跳过本节,因为它不是理解本教程其余部分所必需的。要说明此过程并了解 Brython 的内部结构,请执行以下步骤:

  1. 打开Brython 主页
  2. 与打开Web控制台CmdAlt+I Mac或CtrlShift+I在Windows和Linux。

在浏览器 JavaScript REPL 中,键入并执行以下代码:

> eval(__BRYTHON__.python_to_js("import browser; browser.console.log('Hello Brython!')"));

python_to_js()将提供的 Python 代码解析并编译为 JavaScript,然后在 Web 浏览器中执行 JavaScript。你应该得到以下结果:

将 Python 评估为 JavaScript

应用eval()到 Brython 代码打印"Hello Brython!"在浏览器控制台中。该JavaScript函数返回undefined,这是在JavaScript函数的默认返回值。

在构建 Brython 应用程序时,您不需要显式调用__BRYTHON__JavaScript 模块中的函数。提供此示例仅用于演示 Brython 如何在幕后运作。意识到__BRYTHON__可以帮助您阅读 Brython 代码,甚至可以在您获得更多经验时为项目做出贡献。它还将帮助您更好地了解浏览器控制台中可能显示的异常。

JavaScript__BRYTHON__对象在 JavaScript 全局范围内可用,您可以使用浏览器 JavaScript 控制台访问它。

在浏览器中使用 Brython

至此,您对 Brython 有了足够的了解,可以使用更详细的示例。在本节中,您将实现一个Base64计算器,以在浏览器中试验 DOM API 和其他通常只能从 JavaScript 获得的功能。

您可以通过单击以下链接下载本教程中示例的源代码:

您将首先学习如何使用 Python 和 HTML 操作 DOM。

Brython 中的 DOM API

为了试验 Brython 中可用的 DOM 操作,您将构建一个表单来将字符串编码为Base64。完成的表格将如下所示:

表格 Base64 计算器

创建以下 HTML 文件并将其命名为index.html

 1<!-- index.html -->
 2<!DOCTYPE html >
 3<html>
 4  <head>
 5    <meta charset="utf-8"/>
 6    <link rel="stylesheet"
 7          href="https://cdnjs.cloudflare.com/ajax/libs/pure/2.0.3/pure-min.css" />
 8    <script
 9        src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js">
10    </script>
11    <script
12        src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython_stdlib.min.js">
13    </script>
14    <script src="main.py" type="text/python" defer></script>
15    <style>body { padding: 30px; }</style>
16  </head>
17  <body onload="brython()">
18    <form class="pure-form" onsubmit="return false;">
19      <fieldset>
20        <legend>Base64 Calculator</legend>
21        <input type="text" id="text-src" placeholder="Text to Encode" />
22        <button
23          type="submit" id="submit"
24          class="pure-button pure-button-primary"
25          autocomplete="off">Ok</button>
26        <button id="clear-btn" class="pure-button">Clear</button>
27      </fieldset>
28    </form>
29    <div id="b64-display"></div>
30  </body>
31</html>

上面的 HTML 加载静态资源,定义 UI 布局,并启动 Python 编译:

  • 第 7 行加载PureCSS样式表以改进默认的 HTML 样式。这不是 Brython 工作所必需的。

  • 第 9 行加载 Brython 引擎的最小化版本。

  • 第 12 行加载 Brython 标准库的最小化版本。

  • 第 14 行加载main.py,处理这个静态 HTML 页面的动态逻辑。注意使用defer. 它有助于同步资源的加载和评估,有时需要确保 Brython 和任何 Python 脚本在执行之前完全加载brython()

  • 第 21 行描述了一个input字段。该字段将要编码的字符串作为参数。

  • 第 22 到 25 行定义了button触发页面主要逻辑的默认值。您可以在main.py下面看到此逻辑实现。

  • 第 26 行定义了一个button清除页面上的数据和元素。这在main.py下面实现。

  • 第 29行将 a 声明div为表的占位符。

相关的 Python 代码 ,main.py如下所示:

 1from browser import document, prompt, html, alert
 2import base64
 3
 4b64_map = {}
 5
 6def base64_compute(_):
 7    value = document["text-src"].value
 8    if not value:
 9        alert("You need to enter a value")
10        return
11    if value in b64_map:
12        alert(f"'The base64 value of '{value}' already exists: '{b64_map[value]}'")
13        return
14    b64data = base64.b64encode(value.encode()).decode()
15    b64_map[value] = b64data
16    display_map()
17
18def clear_map(_) -> None:
19    b64_map.clear()
20    document["b64-display"].clear()
21
22def display_map() -> None:
23    table = html.TABLE(Class="pure-table")
24    table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
25    table <= (html.TR(html.TD(key) + html.TD(b64_map[key])) for key in b64_map)
26    base64_display = document["b64-display"]
27    base64_display.clear()
28    base64_display <= table
29    document["text-src"].value = ""
30
31document["submit"].bind("click", base64_compute)
32document["clear-btn"].bind("click", clear_map)

Python 代码显示了回调函数的定义和操作 DOM 的机制:

  • 第 1 行导入用于与 DOM 和浏览器 API 代码交互的模块brython.min.js

  • 第 2 行导入base64,可在 Brython 标准库brython_stdlib.min.js.

  • 第 4 行声明了一个字典,您将使用它在 HTML 页面的生命周期中存储数据。

  • 第 6 行定义了事件处理程序base64_compute(),它用 ID 对输入字段中输入的文本的 Base64 值进行编码text-src。这是一个以事件为参数的回调函数。此参数未在函数中使用,但在 Brython 中是必需的,在 JavaScript 中是可选的。按照惯例,您可以_用作虚拟占位符。Google Python Style Guide 中描述了这种用法的一个示例。

  • 第 7 行检索用 标识的 DOM 元素的值text-src

  • 第 18 行定义了事件处理程序clear_map(),它清除此页面上的数据和数据的呈现。

  • 第 22 行定义了display_map(),它获取 中包含的数据b64_map并将其显示在页面上的表单下。

  • 第 26 行检索具有 ID 的 DOM 元素text-src

  • 第 29 行清除 ID 为 DOM 元素的值text-src

  • 第31个绑定onclick事件中的submit按钮base64_compute()

  • 第 32行将按钮的onclick事件绑定clear-btnclear_map()

为了操作 DOM,Brython 使用了两个操作符:

  1. <=是一个新的运算符,特定于 Brython,用于将子节点添加到节点。您可以display_map()在第 22 行定义的 中看到此用法的一些示例。

  2. +是替代Element.insertAdjacentHTML('afterend')并添加兄弟节点。

您可以在以下语句中看到这两个运算符display_map()

table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))

您可以将上面的代码理解为“向表格元素添加一个表格头元素,其中包含一个由两个相邻表格数据单元格元素组成的表格行元素。它在浏览器中呈现为以下 HTML 代码:

<table>
<thead><tr><th>Text</th><th>Base64</th></tr></thead>
</table>

HTML 代码显示了表格元素标题行的嵌套结构。这是相同代码的更具可读性的格式:

<table>
  <thead>
    <tr>
      <th>Text</th>
      <th>Base64</th>
    </tr>
  </thead>
</table>

要在 Brython 控制台中观察结果,可以输入以下代码块:

>>>
>>> from browser import html
>>> table = html.TABLE()
>>> table <= html.THEAD(html.TR(html.TH("Text") + html.TH("Base64")))
>>> table.outerHTML
'<table><thead><tr><th>Text</th><th>Base64</th></tr></thead></table>'

要执行完整代码,您需要启动 Web 服务器。和以前一样,您在与两个文件相同的目录中启动内置 Python Web 服务器,index.html然后main.py

$ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

启动 Web 服务器后,将浏览器指向http://localhost:8000. 该页面如下所示:

表格 Base64 计算器

您将通过允许在页面重新加载之间存储数据来扩展浏览器 Web API部分中的此示例。

在 Brython 中导入

您可以使用import来访问编译为 JavaScript 的 Python 模块或 Brython 模块。

Python 模块.py在项目的根文件夹中具有扩展名的文件,或者对于 Python 包,在包含__init__.py文件的子文件夹中。要在您的 Brython 代码中导入 Python 模块,您需要启动一个 Web 服务器。有关 Python 模块的更多信息,请查看Python Modules and Packages – An Introduction

要探索如何将 Python 模块导入您的 Brython 代码,请按照使用 PyPI 安装部分中描述的说明进行操作,创建并激活 Python 虚拟环境,安装 Brython,并index.html进行如下修改:

<!doctype html>
<html>

<head>
<meta charset="utf-8">
<script type="text/javascript" src="brython.js"></script>
<script type="text/javascript" src="brython_stdlib.js"></script>
</head>

<body onload="brython()">

<script type="text/python">
from browser import document, html, window
import sys
import functional

selection = functional.take(10, range(10000))
numbers = ', '.join([str(x) for x in selection])

document <= html.P(f"{sys.version=}")
document <= html.P(f"{numbers=}")
</script>

</body>

</html>

上面的 HTML 文件公开了从核心引擎 ( browser)、标准库 ( sys) 和本地 Python 模块 ( functional)导入的模块。以下是内容functional.py

import itertools

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(itertools.islice(iterable, n))

这个模块实现take(),在一个itertools食谱take()返回给定可迭代对象的前n 个元素。它依赖于itertools.slice().

如果您尝试index.html使用浏览器从文件系统打开,则会在浏览器控制台中收到以下错误:

Traceback (most recent call last):
  File file:///Users/andre/brython/code/import/index.html/__main__
  line 3, in <module>
    import functional
ModuleNotFoundError: functional

导入 Python 模块需要启动本地 Web 服务器。启动本地 Web 服务器并将浏览器指向http://localhost:8000. 您应该会看到以下 HTML 页面:

Python 导入

使用正在运行的 Web 服务器,浏览器能够functional.pyimport functional执行时获取模块。值sys.version和的结果numbers由嵌入式 Python 脚本的最后两行插入到 HTML 文件中,并由浏览器呈现。

Reduce Import Size

在上例的项目目录中,为了减小导入的 JavaScript 模块的大小以及将 Python 模块预编译为 JavaScript,您可以使用brython-cli选项--modules

$ brython-cli --modules
Create brython_modules.js with all the modules used by the application
searching brython_stdlib.js...
finding packages...
script in html index.html

这将生成brython_modules.js,您可以修改如下head元素index.html

 1<head>
 2<meta charset="utf-8">
 3<script type="text/javascript" src="brython.js"></script>
 4<script type="text/javascript" src="brython_modules.js"></script>
 5</head>

第 4 行将原始脚本源从 更改brython_stdlib.jsbrython_modules.js

index.html使用浏览器打开或将浏览器指向本地服务器会呈现相同的 HTML 页面。注意以下几点:

  1. 您可以在浏览器中呈现 HTML 页面,而无需运行 Web 服务器。
  2. 你并不需要分发functional.py因为代码已被转换为JavaScript和捆绑brython_modules.js
  3. 您不需要加载brython_stdlib.js.

命令行工具brython-cli --modules提供了一种解决方案,可以从标准库中删除不必要的代码,并将您的 Python 模块编译为 JavaScript 代码。这有助于打包您的应用程序并导致较小的资源下载。

注意:与导入 Python 模块类似,加载带有 HTMLscript元素的 Python 模块需要您启动 Web 服务器。考虑以下 HTMLscript元素:

<script src="main.py" type="text/python"></script>

当执行 Brython 函数并加载script指向 Python 文件的内容时,它会尝试执行只能在 Web 服务器运行时执行的 Ajax 调用。如果您尝试从文件系统打开文件,则浏览器 JavaScript 控制台中会显示类似于以下内容的错误:

IOError: can't load external script at file:///project/main.py
(Ajax calls not supported with protocol file:///)

安全保护可防止您从main.py本地文件系统加载。您可以通过运行本地文件服务器来解决此问题。有关此行为的更多信息,请参阅Brython 文档

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。