Mojo 学习笔记(九)

Mojo 学习笔记(九)

编程文章jaq1232025-05-24 12:43:272A+A-

从 Mojo 中集成 Python

Mojo 的长期目标就是作为 Python 的超集,也就是说可以兼容现有的 Python 程序,现有 Python 程序无需更改就可以用 Mojo 来编译执行,这样就可以在Mojo 中利用到当前庞大的 Python 生态。但目前 Mojo 还在早期开发中,很多Python的特性还没能实现,而且 Mojo 目前也没有自己的生态。因此,现在做法是:Mojo 提供了一种 导入 Python 中 module,并且与之交互的机制,而这些 Python 代码是使用标准的 Python解释器(CPython)来运行的,因此现有的 Python 代码无需任何改动。

from python import Python

fn use_array() raises:
    # This is equivalent to Python's `import numpy as np`
    var np = Python.import_module("numpy")

    # Now use numpy as if writing in Python
    var array = np.array([1, 2, 3])
    print(array)
fn main():
   try:
       use_array()
   except:
       print("failed")                                                 
   finally:
       print("fianlly")

$ mojo 9-1.mojo   
[1 2 3]

上例中,就 导入了 Python 中常用的 numpy 包,并可以使用 numpy 中的各项功能。

这里有几点要注意的:

  • 目前不支持导入独立的成员(例如包里的一个类或者方法),你只能导入整个 Python 包,然后通过包名来访问其中的成员。
  • Mojo 目前还不支持顶层代码,也就是 import_module() 必须在一个函数中调用。这意味着如果在多个函数中要使用Python代码时,你只能多次重复导入,或者在函数之间传递 module 的引用。当然,和 Python 一样,多次导入一个module并不会多次调用这个包的初始化逻辑,因此并不会有太多的性能损失。
  • import_module() 可能会抛出异常(例如包不存在)。因此必须在 fn 中使用try/catch机制,或者在函数签名处增加 raises 关键字。在调用 Python 代码时如果会抛出异常的,也需要这样处理。异常处理机制和 Python 一样,都是 try/except/finally。
  • 除了导入 Python 的包外,也可以通过 import_module()导入本地的 Python 代码,但是需要使用 Python.add_to_path("path/to/module") 来增加 module 的路径。这和 Python 中要导入一个本地的 Python Module 概念是一样的。
  • Mojo SDK 依赖已安装好的Python环境,并通过对接 CPython 的动态库(.so 或者 .dylib) 来使用CPython解释器。

从Python中调用Mojo

从 Python 中可以调用 Mojo 代码吗?答案是否定的。

但还是有可能会希望能够从 Python 中调用 Mojo 的情况的。例如,一般框架会用一些回调函数的方式来实现用户定制的操作,如果使用的是 Python 的框架,用户定制的回调函数用 Mojo 来写,那就尴尬了。Mojo 目前也没有提出什么好的方法来,它文档中举的一个替代方案是让 Mojo 来驱动事件循环,然后在相应的地方分别调用 Python 代码或者 Mojo 代码。但并不是所有的需求都是能用这种方案替代的,不知道未来是否有更好的方案。

Python 类型和Mojo 类型

Mojo 的基础类型都会隐式转换为 Python 的类型,支持例如 List,Tuple, Integer, Float, Boolean 和 String。

比如一个Python 文件 m9-2.py,定义了一个打印 Python 值的类型的函数:

def type_printer(value) :
    print(type(value))

通过Mojo脚本来调用此 Python 文件中的函数:

from python import Python

def main():
    Python.add_to_path("./")
    m = Python.import_module("m9-2")
    m.type_printer(4)
    m.type_printer(3.14)
    m.type_printer(("Mojo", True))

输出:

<class 'int'>
<class 'float'>
<class 'tuple'>

在Mojo中也可以使用Python的类型。例如 Mojo 暂时不支持字典类型,那么就可以直接使用 Python 的 dict 类型。

from python import Python

fn use_dict() raises:
    var dictionary = Python.dict()
    dictionary["fruit"] = "apple"
    dictionary["starch"] = "potato"
    print("Fruit: ", dictionary["fruit"])

当你在Mojo代码中使用Python对象时,Mojo会在Python对象外面增加一个PythonObject 的包装器。该对象暴露了许多常见的双重下划线方法(Dunder方法),例如__getitem__() 和__getattr __(),并将它们传递到基础的Python对象。你也可以显式地定义 PythonObject:

from python.object import PythonObject

var py_list: PythonObject = [1, 2, 3, 4]
var n = py_list[2]
py_list.append(5)

如果你创建的Python类型在Mojo中没有对应的类型,你也可以使用 Python.evaluate(), 例如:

fn use_py_set() raises:
    var py_set = Python.evaluate('set([2, 3, 5, 7, 11])')
    var num_items = len(py_set)
    print(num_items, " items in set.")  # prints "5 items in set"
    print(py_set.__contains__(6))       # prints "False"
点击这里复制本文地址 以上内容由jaq123整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

苍茫编程网 © All Rights Reserved.  蜀ICP备2024111239号-21