如何从内存加载已编译的python模块?

如何从内存加载已编译的python模块?,第1张

如何从内存加载已编译的python模块

这取决于您所拥有的“模块(预编译)”的确切含义。假设它恰好是

.pyc
文件的内容,例如,
ciao.pyc
通过以下方式构建:

$ cat>'ciao.py'def ciao(): return 'Ciao!' $ python -c'import ciao; print ciao.ciao()'Ciao!

IOW这样构建后

ciao.pyc
,说您现在要做:

$ pythonPython 2.5.1 (r251:54863, Feb  6 2009, 19:02:12) [GCC 4.0.1 (Apple Inc. build 5465)] on darwinType "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<pre 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
语句内部结构本身的机制-
这也是可行的,但并不完全是您要问的,所以在这里,我也希望您能通过简单的方法来简化生活,如答案所示。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5647325.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存