• PythonMonkey:可以实现 Python 和 JavaScript互操作的Python库
  • 发布于 2个月前
  • 454 热度
    0 评论
最近在 Github 上发现一个非常有意思的项目 PythonMonkey ,它可以让我们直接在 JavaScript 中运行 Python 代码,也可以在 Python 中运行 JavaScript 和 WebAssembly 代码,而且几乎没有性能损失。

PythonMonkey 是一个 Python 库,它使用 Mozilla 的 SpiderMonkey JavaScript 引擎构建,可以实现 Python 和 JavaScript 之间的互操作。它可以让 JavaScript 库能够在 Python 代码中无缝使用,反之亦然,而不会造成比较大的性能损失。例如,我们可以从 JavaScript 库中调用 NumPy 等 Python 包,或者直接从 Python 中使用 crypto-js 等 NPM 包。此外,使用 WebAssembly API 和 SpiderMonkey 引擎在 Python 中执行 WebAssembly 模块也变得非常简单。开发者也可以使用 PythonMonkey 重构用 Python 编写的代码改为在 JS 中执行,利用 SpiderMonkey 的即时编译器获得接近原生的速度。

PythonMonkey 还附带了 PMJS,这是一个类似于 Node.js 的 JavaScript 运行时环境,支持从 JavaScript 调用 Python 库。

下面是一个简单的 “hello world”示例,演示了从 JavaScript 生成的字符串并返回到 Python 上下文:
>>> import pythonmonkey as pm 
>>> hello = pm.eval(" 'Hello World'.toUpperCase(); ") 
>>> print(hello) 
'HELLO WORLD'
下面是一个复杂一点的示例,演示了将 Python print 函数作为参数传递给 JavaScript 函数,然后从 Python 调用该 JavaScript 函数:
>>> import pythonmonkey as pm 
  >>> hello = pm.eval("(func) => { func('Hello World!')}") 
  >>> hello(print) 
Hello World!
通过下面的写法我们可以直接在 JavaScript 代码中使用 Python 的 print 函数:
const pyPrint = python.eval("print");
pyPrint("Hello, World!"); // this outputs "Hello, World!"
我觉得一个比较实用的应用场景就是我们可以轻松地将一个 JavaScript 库移植到 Python,而不需要承受使用 Python 重写库和维护迁移的巨大成本。JavaScript 比 Python 处理异步代码的能力要好很多。我们只需要做下面这样简单的操作:

my-javascript-module.js
exports.sayHello = () => { console.log('hello, world') };
main.py

import pythonmonkey as pm
test = pm.require('./my-javascript-module');
test.sayHello() # this prints hello, world
同样的,我们可以从 JavaScript 中通过 CommonJS 加载一个 Python 模块:

my-python-module.py
def getStringLength(s):
  return len(s)

exports['getStringLength'] = getStringLength
my-javascript-module.js

const { getStringLength } = require('./my-python-module');

function printStringLength(s) {
  console.log(`String: "${s}" has a length of ${getStringLength(s)}`);
}

module.exports = { printStringLength, };
main.py
import pythonmonkey as pm
test = pm.require('./my-javascript-module');
test.printStringLength("Hello, world!") # String: "Hello, world!" has a length of 13
PythonMonkey 还利用了一些其他的 SpiderMonkey 功能,例如它的 WebAssembly (WASM) 引擎,它可以允许 Python 在沙箱中运行来自各种语言(例如 C、C++、Rust 等)的不受信任的 WASM 代码。

在 Python 中调用 WebAssembly 函数:
import asyncio
import pythonmonkey as pm
 # 堆代码 duidaima.com
async def async_fn():
  # read the factorial.wasm binary file
  file = open('factorial.wasm', 'rb')
  wasm_bytes = bytearray(file.read())

  # instantiate the WebAssembly code
  WebAssembly = pm.eval('WebAssembly')
  wasm_fact = await WebAssembly.instantiate(wasm_bytes, {})

  # return the "fac" factorial function from the wasm module
  return wasm_fact.instance.exports.fac;

# await the promise which returns the factorial WebAssembly function
factorial = asyncio.run(async_fn())

# execute WebAssembly code in Python!
print(factorial(4)) # this outputs "24.0" since factorial(4) == 24
print(factorial(5)) # this outputs "120.0"
print(factorial(6)) # this outputs "720.0"
还有更多的示例,我们可以查看 Github 上的例子:https://github.com/Distributive-Network/PythonMonkey-examples

目前已经有几个用于在 Python 中运行 JavaScript 的项目了,例如 JS2PY、PyV8 和 Metacall。
JS2Py 完全用 Python 实现,它消除了对 V8 或 SpiderMonkey 等大型引擎的需求。但是这种方法也有一些问题,如果不利用现有的 JavaScript 引擎,JS2Py 就无法从 V8 或 SpiderMonkey 等引擎在数百万人每天使用的浏览器中提供的强大、不断更新且经过验证的代码库中受益。此外,JS2Py 还缺少 WASM 引擎、对最新 JavaScript 规范 (ECMA-262) 的支持以及这些引擎内置的强大 JIT 等功能。现代异步 JS 编程中广泛使用的 JavaScript Promises 和 Async/Await 在 JS2Py 中也是缺失的,但在 PythonMonkey 中是可用的。使用 Python 编写,JS2Py 面临 SpiderMonkey 中不存在的性能限制;在 SunSpider JavaScript 基准测试报告显示:使用 PythonMonkey 比 JS2Py 快了 1162.5 倍。

PyV8 和 Cloudflare 的现代实现是 Google V8 JavaScript 引擎绑定的 Python 包装器。这意味着它的运行级别比 PythonMonkey 更低,并且不支持事件循环功能,例如 JavaScript 的 Promise 和 async/await。

Metacall 是一个可扩展、可嵌入和可互操作的跨平台多语言运行时,可与多种编程语言(例如 JavaScript、Python、Ruby、Rust、C#、Java 等)进行互操作。但是 Metacall 支持的广泛支持语言也是有代价的,并且需要在 Python 包之外的系统上安装额外的软件才能运行。此外,Metacall 会复制在 Python 和 JavaScript 之间传递的数据,而不是像 PythonMonkey 那样通过引用传递,从而导致性能影响。

虽然替代项目与 PythonMonkey 的模型有相似之处,但它们达不到 PythonMonkey 提出的互操作性、易用性和速度。

最后
参考:https://github.com/Distributive-Network/PythonMonkey/
大家觉得这个项目如何呢?欢迎在评论区留言。
用户评论