使用字节码而不是源代码导入Python模块

5

来自Python书籍:

学习Python. 第5版, 第727页

我读到了以下内容:

如果Python在搜索路径上只找到一个字节码文件而没有源代码,它会直接加载该字节码;这意味着你可以仅发送字节码文件作为程序并避免发送源代码。

但是,在Python 3.5上尝试相同的操作时,它无法工作:

~/Python/Module_Test$ cat a.py
a = "abc"
l = [1,2,3]

导入模块'a'会创建以下字节码文件:

~/Python/Module_Test/__pycache__$ ls
a.cpython-35.pyc

现在我已经删除了 'a.py' 文件,并且从字节码目录中导入模块 'a'

~/Python/Module_Test/__pycache__$ python
Python 3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul  2 2016, 17:53:06) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'a'

我甚至尝试将字节码目录添加到搜索路径中,但仍无法加载该模块:
>>> import sys
>>> sys.path.append('/home/pradeep/Python/Module_Test/__pycache__')
>>> import a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'a'

我做错了什么?我们能否从字节码中导入模块而不需要源代码?我的理解是否有误?

我不使用Anaconda,但是当使用标准的CPython解释器时,字节码文件名与源文件名相同,只是在末尾添加了一个“c”,即“a.py”编译为“a.pyc”。尝试创建一个名为“a.pyc”的链接指向“a.cpython-35.pyc”,或者直接将“a.cpython-35.pyc”重命名为“a.pyc”,看看会发生什么。 - PM 2Ring
根据我所了解的,这是标准的Python行为,@PM2Ring,通过修改名称来实现根据解释器版本生成不同的字节码版本。 - Dimitris Fasarakis Hilliard
仅发布字节码而不包含源代码是自找麻烦。字节码不能保证在不同平台、Python 实现或版本之间的可移植性。 - cdarke
@PM2Ring Python 3.x 字节码被移动到 'pycache' 目录,并附加了 Python 版本号。
pradeep@ubuntu:~/Python/Module_Test$ ls pycache/
a.cpython-34.pyc a.cpython-35.pyc
- Pradeep
2个回答

2
在删除 'a.py' 后,您需要将 'a.pyc' 放在相同的位置。当解释器执行 'import a' 时,导入机制会看到它并成功导入。这样做不需要引用缓存。
要获取 'a.pyc',请查看 pycache 并将 'a.xxxx.pyc' 复制到文件夹并重命名为 'a.pyc'。还有一个编译成字节码的 Python 函数,因此您不必使用 pycache
只要您的 Python 安装没有更改,这应该可以正常工作。我认为 '.pyc' 文件的格式可能因安装而异。我认为这是一种传输字节码而不是源代码的方法。但是,您必须保留目录结构和 'pyc' 文件与相应 'py' 文件放置在相同目录中的位置。当然,目标计算机必须安装适当的 Python 版本。

1
你的理解并没有错;你可以这样做,但这不是最好的做法。据我所知,import语句的默认行为并不会自动执行这个操作,你需要使用imp中的一个已弃用的函数、编写自己的函数或自定义导入过程来完成它。
使用imp,你可以这样使用load_compiled:
from imp import load_compiled

mod = load_compiled('a', '__pycache__/a.cpython-35.pyc')

为了导入你的模块。我知道Python做的一个显著的事情是,如果相应的*.pyc文件存在且仍然有效,则不会重新编译模块a.py。

1
我并不打算在生产环境中这样做。我正在努力理解作者关于使用字节码导入模块而不需要源代码的说法。 - Pradeep
@Pradeep_Evol 啊,我明白了,那就没问题了 :-) - Dimitris Fasarakis Hilliard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接