我需要从zipfile(由py2exe压缩构建)读取所有模块(预编译)到内存中然后加载它们.我知道这可以通过从zipfile直接加载来完成,但我需要从内存中加载它们.有任何想法吗?(我在Windows上使用python 2.5.2)TIA Steve
Ale*_*lli 31
这取决于你所拥有的"模块(预编译)".让我们假设它正是.pyc文件的内容,例如,ciao.pyc由以下内容构建:
$ cat>'ciao.py'
def ciao(): return 'Ciao!'
$ python -c'import ciao; print ciao.ciao()'
Ciao!
Run Code Online (Sandbox Code Playgroud)
IOW,这样建成ciao.pyc,说你现在做:
$ 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
Run Code Online (Sandbox Code Playgroud)
并且您的目标是从该字节字符串b转到可导入的模块ciao.这是如何做:
>>> import marshal
>>> c = marshal.loads(b[8:])
>>> c
<code object <module> at 0x65188, file "ciao.py", line 1>
Run Code Online (Sandbox Code Playgroud)
这是从.pyc二进制内容中获取代码对象的方法. 编辑:如果你很好奇,前8个字节是一个"幻数"和一个时间戳 - 这里不需要(除非你想要理智 - 检查它们并在有保证的情况下引发异常,但这似乎超出了问题的范围; marshal.loads如果它检测到损坏的字符串,无论如何都会提高).
然后:
>>> import types
>>> m = types.ModuleType('ciao')
>>> import sys
>>> sys.modules['ciao'] = m
>>> exec c in m.__dict__
Run Code Online (Sandbox Code Playgroud)
即:创建一个新的模块对象,安装它sys.modules,通过执行其中的代码对象来填充它__dict__. 编辑:你进行sys.modules插入的顺序,exec当且仅当你可能有循环导入时 - 但是,这是Python自己import通常使用的顺序,因此最好模仿它(没有特定的缺点).
你可以用几种方式"创建一个新的模块对象"(例如,来自标准库模块中的函数,如new和imp),但"调用类型来获取实例"是目前正常的Python方式,并且是正常的获取位置来自标准库模块的类型(除非它有一个内置名称,否则你已经很方便)types,所以这就是我推荐的.
现在,最后:
>>> import ciao
>>> ciao.ciao()
'Ciao!'
>>>
Run Code Online (Sandbox Code Playgroud)
...您可以导入模块并使用其功能,类等.然后其他import(和from)语句将找到该模块sys.modules['ciao'],因此您不需要重复此操作序列(如果您只想确保该模块可从其他地方导入,那么您在此处不需要此最后一个import语句 - 我添加它只是为了表明它有效;-).
编辑:如果你绝对必须以这种方式导入包和模块,而不是像我刚刚展示的"普通模块",那也是可行的,但有点复杂.由于这个答案已经很长了,我希望你可以通过坚持这个目的的简单模块来简化你的生活,我会推卸答案的那一部分;-).
另请注意,在"多次从内存加载相同模块"的情况下,这可能会或可能不会执行您想要的操作(每次重建模块;您可能需要检查sys.modules,如果模块已经存在,则跳过所有内容并且特别是当从多个线程(需要锁定)发生这样的重复"从内存加载"时 - 但是,更好的架构是具有专用于执行任务的单个专用线程,其他模块通过队列与其通信).
最后,没有讨论如何将此功能安装为透明的"导入钩子",它自动参与import语句内部机制本身 - 这也是可行的,但不完全是你所要求的,所以在这里,同样,我希望你可以通过简单的方式来简化你的生活,正如这个答案所概述的那样.
编译的Python文件包含
要加载模块,你必须创建模块对象imp.new_module(),在新模块的命名空间中执行unmashaled代码并将其放入sys.modules.下面的示例实现:
import sys, imp, marshal
def load_compiled_from_memory(name, filename, data, ispackage=False):
if data[:4]!=imp.get_magic():
raise ImportError('Bad magic number in %s' % filename)
# Ignore timestamp in data[4:8]
code = marshal.loads(data[8:])
imp.acquire_lock() # Required in threaded applications
try:
mod = imp.new_module(name)
sys.modules[name] = mod # To handle circular and submodule imports
# it should come before exec.
try:
mod.__file__ = filename # Is not so important.
# For package you have to set mod.__path__ here.
# Here I handle simple cases only.
if ispackage:
mod.__path__ = [name.replace('.', '/')]
exec code in mod.__dict__
except:
del sys.modules[name]
raise
finally:
imp.release_lock()
return mod
Run Code Online (Sandbox Code Playgroud)
更新:更新代码以正确处理包.
请注意,您必须安装导入钩子来处理已加载模块中的导入.一种方法是将你的取景器添加到sys.meta_path.有关更多信息,请参阅PEP302.
| 归档时间: |
|
| 查看次数: |
7122 次 |
| 最近记录: |