很遗憾,不能自动完成这项操作。你当然可以手动完成,但是这样做的话会很麻烦且难看。
设置:
为了演示目的,我将首先生成一个 .pyc
文件。为此,我们首先需要一个相应的 .py
文件。我们的示例 test.py
文件如下:
def foo():
print("In foo")
if __name__ == "__main__":
print("Hello World")
非常简单。使用标准库中的py_compile
模块可以生成.pyc
文件。我们只需按照以下方式传入.py
文件的名称和我们的.pyc
文件的名称即可:
py_compile.compile('test.py', 'mypyc.pyc')
这将把mypyc.pyc
放置在我们当前的工作目录中。
从.pyc
文件获取代码:
.pyc
文件包含按以下方式结构化的字节:
- 前4个字节表示“魔数”
- 接下来的4个字节保存修改时间戳
- 剩余的内容是一个编组的
code
对象。
我们想要的是那个编组的code
对象,因此我们需要import marshal
对其进行解编组并执行。此外,我们真的不关心/不需要前8个字节,并且使用它们对.pyc
文件进行解编组被禁止,因此我们将忽略它们(seek
越过它们):
import marshal
s = open('mypyc.pyc', 'rb')
s.seek(8)
code_obj = marshal.load(s)
现在我们有了一个漂亮的code
对象,可供test.py
使用,并且已经准备好按我们的意愿执行。这里我们有两个选择:
在当前的global
命名空间中执行它。这将绑定我们.pyc
文件内所有定义到当前命名空间中,并充当一种类似于:from file import *
语句的作用。
创建一个新的模块对象并在模块内执行代码。这将类似于import file
语句。
模拟from file import *
的行为:
要执行此操作非常简单,只需执行以下操作:
exec(code_obj)
这将在当前命名空间中执行code_obj
中包含的代码并绑定所有变量。调用后,我们可以像调用其他函数一样调用foo
:
foo()
注意: exec()
是一个内置函数。
模拟 import file
行为:
这需要另一个要求,即使用 types
模块。该模块包含类型ModuleType
,我们可以用它来创建一个新的模块对象。它接受两个参数,模块的名称(必填)和文档(可选):
m = types.ModuleType("Fancy Name", "Fancy Documentation")
print(m)
<module 'Fancy Name' (built-in)>
现在我们有了模块对象,我们可以再次使用 exec
来执行 code_obj
中包含的代码,执行的命名空间是模块命名空间(即 m.__dict__
):
exec(code_obj, m.__dict__)
现在,我们的模块m
中拥有了code_obj
中定义的所有内容,您可以通过运行以下代码进行确认:
m.foo()
以下是包含 .pyc
文件到您的模块中的方式。至少,这是我能想到的几种方式。我并不真正看到这样做的实用性,但是嘿,我不在这里评判。