如何在Python中从代码对象生成模块对象

16 投票
1 回答
8815 浏览
提问于 2025-04-15 19:36

假设我有一个模块的代码对象,我该如何获取对应的模块对象呢?

看起来像是 moduleNames = {}; exec code in moduleNames 这样的写法很接近我想要的效果。它会把模块中声明的全局变量放到一个字典里。但是如果我想要实际的模块对象,我该怎么做呢?

编辑:
看起来你可以自己创建一个模块对象。虽然模块类型的文档不是很方便,但你可以尝试这样做:

import sys
module = sys.__class__
del sys
foo = module('foo', 'Doc string')
foo.__file__ = 'foo.pyc'
exec code in foo.__dict__

1 个回答

26

正如评论中提到的,现在在Python中,创建没有内置名称的类型的推荐方法是通过标准库中的types模块来调用类型:

>>> import types
>>> m = types.ModuleType('m', 'The m module')

需要注意的是,这并不会自动将新模块插入到sys.modules中:

>>> import sys
>>> sys.modules['m']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'm'

这个步骤你需要手动完成:

>>> sys.modules['m'] = m
>>> sys.modules['m']
<module 'm' (built-in)>

这一步很重要,因为模块的代码通常是在模块被添加到sys.modules之后执行的——例如,代码中引用sys.modules[__name__]是完全正确的,但如果你忘了这一步就会出错(KeyError)。在完成这一步之后,并且像你在编辑中已经做的那样设置m.__file__

>>> code = compile("a=23", "m.py", "exec")
>>> exec code in m.__dict__
>>> m.a
23

(或者在Python 3中,exec是一个函数,如果你使用的是Python 3的话;-) 这样做是正确的(当然,你通常会通过更微妙的方式获得代码对象,而不是简单地编译一个字符串,但这和你的问题无关;-)。

在旧版本的Python中,你会使用new模块来创建一个新的模块对象,但自从Python 2.6起,new模块就被弃用了,并在Python 3中被移除了。

撰写回答