这取决于您所拥有的“模块(预编译)”的确切含义。假设它恰好是.pyc
文件的内容,例如,Ciao.pyc
通过以下方式构建:
$ cat>'Ciao.py'
def Ciao(): return 'Ciao!'
$ python -c'import Ciao; print Ciao.Ciao()'
Ciao!
$ python
Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> b = open('Ciao.pyc', 'rb').read()
>>> len(b)
200
而您的目标是从该字节字符串b
转到可导入模块Ciao
。这是如何做:
>>> import marshal
>>> c = marshal.loads(b[8:])
>>> c
<code object <module> at 0x65188, file "Ciao.py", line 1>
这是从.pyc
二进制内容中获取代码对象的方式。 :如果您很好奇,则前8个字节是一个“幻数”和一个时间戳记- 此处不需要(除非您想进行健全性检查并在必要时提出异常,但这似乎超出了问题的范围) ;marshal.loads
会在检测到损坏的字符串时引发()。
然后:
>>> import types
>>> m = types.ModuleType('Ciao')
>>> import sys
>>> sys.modules['Ciao'] = m
>>> exec c in m.__dict__
即:创建一个新的模块对象,将其安装在其中sys.modules
,然后通过执行其中的代码对象来填充它__dict__
。 :sys.modules
插入的顺序,exec
并且仅在可能具有循环导入的情况下才重要- 但是,这是Python自己import
通常使用的顺序,因此最好模仿它(没有特定的缺点)。
您可以通过几种方式“创建新的模块对象”(例如,从标准库模块中的函数,如new
和imp
),但是“调用类型以获取实例”是当今的常规Python方式,也是获取常规位置的常用方法。 from的类型(除非它具有内置名称,否则您已经很方便了)来自标准库模块types
,因此,我建议这样做。
现在,最后:
>>> import Ciao
>>> Ciao.Ciao()
'Ciao!'
>>>
…您可以导入模块并使用其功能,类等。然后,其他import
(和from
)语句将找到该模块sys.modules['Ciao']
,因此您无需重复此操作序列(实际上,如果您只是想确保该模块可从其他位置导入,则在此不需要 最后一条import
语句) -我添加它只是为了表明它有效;-)。
:如果您绝对必须以这种方式从中导入包和模块,而不是像我刚才所示的“纯模块”,那也是可行的,但是稍微复杂一点。由于这个答案已经很长了,我希望您可以通过为此使用简单的模块来简化您的生活,我将回避答案的那一部分;-)。
还要注意,在“多次从内存中加载同一模块”的情况下,这可能会或可能不会做您想要的(每次都会重新构建模块;您可能要检查sys.modules,如果模块已经存在,则跳过所有内容),尤其是当这种重复的“从内存中加载”是从多个线程中发生时(需要锁- 但更好的体系结构是只有一个专用线程来执行任务,而其他模块则通过队列与之通信)。
最后,没有讨论如何将此功能安装为透明的“导入钩子”,该钩子自动地参与了import
语句内部结构本身的机制- 这也是可行的,但并不完全是您要问的,所以在这里,我也希望您能通过简单的方法来简化生活,如答案所示。