
Mojo 允许您访问整个 Python 生态系统,但环境可能会根据 Python 的安装方式而有所不同。 花一些时间来准确理解模块和包在 Python 中的工作原理是值得的,因为有一些复杂的情况需要注意。 如果您以前在调用 Python 代码时遇到困难,这将帮助您入门。
让我们从 Python 开始,如果同一目录中有两个文件:
├── main.py
└── mod.py
如果 mod.py
有一个函数和一个变量:
def foo(arg):
print(f'arg = {arg}')
bar = [5, 10, 15, 20]
您可以从同一目录中的任何文件调用它:
from mod import foo, bar
foo("test")
bar
输出:
arg = test
[5, 10, 15, 20]
mod.py 被视为名为 mod 的模块。 您还可以导入 sys.path 上的任何模块,让我们看一下:
import sys
sys.path
输出:
['/usr/lib/python311.zip',
'/usr/lib/python3.11',
'/usr/lib/python3.11/lib-dynload',
'/home/j/.local/lib/python3.11/site-packages',
'/usr/lib/python3.11/site-packages',
'/home/j/blog']
因为我从 /home/j/blog 运行 python 解释器,所以这是我的 python 路径上的最后一件事,也是 mod.py 可以访问的原因。
就像您的系统 $PATH 环境变量一样,每个路径都会按降序检查,直到找到您的模块。
如果我们查看 /usr/lib/python3.11 内部,我们将找到 Python 3.11 的标准库:
os.listdir(sys.path[1])[196:200]
输出:
['os.py', 'base64.py', 'tempfile.py', 'pkgutil.py']
那里的所有内容都可以用作模块,因为它位于 sys.path 上,例如我们可以从 tempfile.py 导入一个函数:
from tempfile import mkstemp
tmp = mkstemp(".py")
print("Generated temp file path:", tmp[1])
输出:
Generated temp file path: /tmp/tmp2go6n4ir.py
我们还可以使用环境变量添加到 sys.path 中,以便我们可以访问其他地方的模块:
export PYTHONPATH="/home/j"
如果您检查 sys.path 上的第一个条目,它现在就在那里:
sys.path[0]
输出:
/home/j
您还可以直接编辑 sys.path:
sys.path.append("/tmp")
为了说服自己这有效,在 /tmp/mod2.py 创建一个文件:
a = 42
您现在可以将 mod2 作为模块访问:
import mod2
mod2
输出:
module 'mod2' from '/tmp/mod2.py'
该模块内的任何内容都可以访问:
mod2.a
输出:
module 'mod2' from '/tmp/mod2.py'
该模块内的任何内容都可以访问:
mod2.a
42
直接修改 sys.path 被认为是不好的做法,您应该按预期使用模块系统,但这是了解事物在幕后如何工作的好方法。
有关 Python 如何查找和加载模块和包的更多详细信息,您可以阅读模块搜索路径文档和站点模块文档。 如果您想知道 sys.path 是如何生成的,源代码和 sys path init 文档中对其进行了高级描述。
对于我们的目的来说,最重要的部分是 sys.prefix,它是我们正在使用的 python 二进制文件的 lib 和 bin 文件夹所在的基础:
which python
/usr/bin/python
现在请注意,前缀是 python 可执行文件上方的两个文件夹,这是 sys.path 将开始搜索的根目录:
sys.prefix
/usr
根据您运行的系统,它看起来会非常不同,但您总是会在 sys.prefix 处看到 lib 和 bin,这就是前几个路径(如 /usr/lib/python3.11 和 /usr/)的位置 添加了 lib/python3.11/site-pacakges。 根据上面的文档,有多种方法可以解决这个问题,但这是一般规则。
从 Mojo🔥 调用 Python
在 Mojo 中,我们可以以相同的方式使用 sys.path 中的任何 Python 模块。 要准确确定正在使用哪个环境,我们首先检查前缀:
from python import Python
def main():
let sys = Python.import_module("sys")
print(sys.prefix)
/usr
调用 Python 可能会导致错误,因此我们要么需要使用 def main(): 作为入口点, fn main() raise: 将其标记为可以抛出错误的严格 Mojo 函数,要么在 try 中处理错误 除了块:
fn main():
try:
let x = Python.import_module("fake")
except e:
# mojo 0.3.1
print("Failed to import:", e.value)
# next release
print("Failed to import:", e)
在 Mojo 的下一个版本中,如果出现问题,这将打印来自 Python 的错误,目前,Python 失败时会引发通用错误:
# 0.3.1
Failed to import: An error occurred in Python.
# Next Release
Failed to import: No module named 'fake'
您还可以从 Mojo 打印 sys.path 上的所有内容:
for p in sys.path:
print(p)
/usr/lib/python3.11/site-packages
/usr/lib/python311.zip
/usr/lib/python3.11
/usr/lib/python3.11/lib-dynload
/home/j/.local/lib/python3.11/site-packages
注意到这里有什么不同吗? 我们的当前目录在路径上没有! 您可以使用以下命令添加它:
# Relative Path
Python.add_to_path(".")
# Absolute Path
Python.add_to_path("/home/j/blog")
print(sys.path[-1])
sys.path[-2]
/home/j/blog
.
现在当前的任何模块都可以直接使用,让我们访问我们之前从 Mojo 创建的 mod.py:
let mod = Python.import_module("mod")
mod.bar
[5, 10, 15, 20]
转载:https://www.modular.com/blog/using-mojo-with-python
翻译:谷歌翻译