大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。

什么是 PythonMonkey
A Mozilla SpiderMonkey JavaScript engine embedded into the Python VM, using the Python engine to provide the JS host environment.
PythonMonkey 是嵌入到 Python 运行时的 Mozilla SpiderMonkey JavaScript 引擎,使用 Python 引擎提供 Javascript 宿主环境。
其使用 cPython C API 在 Python 列表和字典上实现 JavaScript 数组和对象方法,并使用 Mozilla Firefox Spidermonkey JavaScript C++ API 实现相反的方法。
截至 2024 年 3 月,PythonMonkey 大约 95% 已达到 MVP,同时 Distributive 正在积极开发该产品。PythonMonkey 的目标是:
- 快速且节省内存
- 让使用 JS 或 Python 编写代码成为开发人员的偏好
- 提供 Python 库 和 JavaScript 库的互操作性
- 同一进程运行 JavaScript 和 Python VirtualMachines ,无需序列化、管道等
- Python 列表和字典行为与 Javacript 数组和对象相同,反之亦然,完全适应给定上下文
目前 PythonMonkey 在 Github 通过 MIT 协议开源,是一个值得关注的开源项目。
如何使用 PythonMonkey
首先通过 PIP 安装包:
pip3 install pythonmonkey
下面示例返回一个 Python 函数,该函数使用 JS new 运算符调用函数:
import pythonmonkey as pm
>>> pm.eval("class MyClass { constructor() { console.log('ran ctor') }}")
>>> MyClass = pm.eval("MyClass")
>>> MyClass()
Traceback (most recent call last):
File "", line 1, in
pythonmonkey.SpiderMonkeyError: TypeError: class constructors must be invoked with 'new'
>>> MyClassCtor = pm.new(MyClass)
>>> MyClassCtor()
ran ctor
{}
>>>
PythonMonkey 目前已经支持所有 JS 标准类(数组、函数、对象、日期等)和对象(globalThis、FinalizationRegistry等),都可以作为 pythonmonkey 模块的导出,其是通过枚举当前 SpiderMonkey 上下文中的全局变量来生成的。 当前的列表是:
undefined, Boolean, JSON, Date, Math, Number, String, RegExp, Error, InternalError, AggregateError, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, ArrayBuffer, Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, Uint8ClampedArray, BigInt64Array, BigUint64Array, BigInt, Proxy, WeakMap, Map, Set, DataView, Symbol, Intl, Reflect, WeakSet, Promise, WebAssembly, WeakRef, Iterator, AsyncIterator, NaN, Infinity, isNaN, isFinite, parseFloat, parseInt, escape, unescape, decodeURI, encodeURI, decodeURIComponent, encodeURIComponent, Function, Object, debuggerGlobal, FinalizationRegistry, Array, globalThis
如果需要运行事件循环可以使用 setTimeout 和 Promise<=>awaitable:
import asyncio
async def async_fn():
await pm.eval("""
new Promise((resolve) => setTimeout((...args) => {
console.log(args);
resolve();
}, 1000, 42, "abc")
)
""")
await pm.eval("async (x) => await x")(asyncio.sleep(0.5))
asyncio.run(async_fn())
更多关于 PythonMonkey 的用法和特性可以参考文末资料,本文不再过多展开。
参考资料
https://github.com/Distributive-Network/PythonMonkey
https://medium.com/@willkantorpringle/pythonmonkey-javascript-wasm-interop-in-python-using-spidermonkey-bindings-4a8efce2e598