前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript 和 Python 代码也能结合使用?

JavaScript 和 Python 代码也能结合使用?

作者头像
ConardLi
发布2023-08-23 13:36:19
4930
发布2023-08-23 13:36:19
举报
文章被收录于专栏:code秘密花园

最近在 Github 上发现一个非常有意思的项目 PythonMonkey ,它可以让我们直接在 JavaScript 中运行 Python 代码,也可以在 Python 中运行 JavaScriptWebAssembly 代码,而且几乎没有性能损失。

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

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

下面是一个简单的 “hello world”示例,演示了从 JavaScript 生成的字符串并返回到 Python 上下文:

代码语言:javascript
复制
>>> import pythonmonkey as pm 
>>> hello = pm.eval(" 'Hello World'.toUpperCase(); ") 
>>> print(hello) 
'HELLO WORLD'

下面是一个复杂一点的示例,演示了将 Python print 函数作为参数传递给 JavaScript 函数,然后从 Python 调用该 JavaScript 函数:

代码语言:javascript
复制
>>> import pythonmonkey as pm 
  >>> hello = pm.eval("(func) => { func('Hello World!')}") 
  >>> hello(print) 
Hello World!

通过下面的写法我们可以直接在 JavaScript 代码中使用 Pythonprint 函数:

代码语言:javascript
复制
const pyPrint = python.eval("print");
pyPrint("Hello, World!"); // this outputs "Hello, World!"

我觉得一个比较实用的应用场景就是我们可以轻松地将一个 JavaScript 库移植到 Python,而不需要承受使用 Python 重写库和维护迁移的巨大成本。JavaScriptPython 处理异步代码的能力要好很多。我们只需要做下面这样简单的操作:

my-javascript-module.js

代码语言:javascript
复制
exports.sayHello = () => { console.log('hello, world') };

main.py

代码语言:javascript
复制
import pythonmonkey as pm
test = pm.require('./my-javascript-module');
test.sayHello() # this prints hello, world

同样的,我们可以从 JavaScript 中通过 CommonJS 加载一个 Python 模块:

my-python-module.py

代码语言:javascript
复制
def getStringLength(s):
  return len(s)

exports['getStringLength'] = getStringLength

my-javascript-module.js

代码语言:javascript
复制
const { getStringLength } = require('./my-python-module');

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

module.exports = { printStringLength, };

main.py

代码语言:javascript
复制
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 函数:

代码语言:javascript
复制
import asyncio
import pythonmonkey as pm

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 的项目了,例如 JS2PYPyV8Metacall

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

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

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

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

最后

参考:https://github.com/Distributive-Network/PythonMonkey/

大家觉得这个项目如何呢?欢迎在评论区留言。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 code秘密花园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档