考虑以下程序来加载目录中的所有模块:
import pkgutil
import os.path
import sys
def load_all(directory):
for loader, name, ispkg in pkgutil.walk_packages([directory]):
loader.find_module(name).load_module(name)
if __name__ == '__main__':
here = os.path.dirname(os.path.realpath(__file__))
path = os.path.join(here, 'lib')
sys.path.append(path)
load_all(path)
现在考虑我们有以下文件。
LIB /魔/ imho.py:
"""This is an empty module.
"""
LIB /魔/ wtf.py:
import magic.imho
print "magic contents:", dir(magic)
LIB /魔/ __ INIT __ PY:
"Empty package init file"
执行上述程序时,输出:
magic contents: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
换句话说,尽管import magic.imho
imho
,但magic
包上没有属性magic.imho
,导致后来对$ PYTHONPATH=lib ipython
Python 2.7.6 (default, Mar 22 2014, 22:59:38)
Type "copyright", "credits" or "license" for more information.
IPython 1.2.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: import magic.wtf
magic contents: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'imho']
的引用失败。
直接在python中运行相同的代码(或多或少)会显示不同的输出,这是我在运行加载程序时所期望的输出。
magic.imho
为什么会有区别?
更新:此处的重点是,magic.wft
内的符号magic.wtf
不存在,尽管它是明确导入的。因此,需要对自定义加载过程执行哪些操作才能使其正常运行并确保符号在setattr
中导入后 。
使用exec
的解决方案: BartoszKP使用exec
为解决方案提供了以下解决方案。由于我通常不喜欢使用setattr
(由于很多原因,注入是第一个)我使用了rpartition
和def load_all(directory):
for loader, name, ispkg in pkgutil.walk_packages([directory]):
module = loader.find_module(name).load_module(name)
pkg_name, _, mod_name = name.rpartition('.')
if pkg_name:
setattr(sys.modules[pkg], mod_name, module)
,如下所示:
{{1}}
答案 0 :(得分:0)
正如this answer中建议更准确地模仿import
正在做的事情,您应修改load_all
方法,如下所示:
def load_all(directory):
for loader, name, ispkg in pkgutil.walk_packages([directory]):
module = loader.find_module(name).load_module(name)
exec('%s = module' % name)
这种方式有效, wtf.py 将在magic
内正确绑定名称。因此,下次导入magic
时,将不会重新加载(因为此函数已将其放入sys.modules
),但它将正确分配所有子模块。
这似乎缓解了import
机制中的一些怪癖,我试图在下面进行诊断。
有效的区别在于,在第一种情况下,模块的加载顺序与第二种情况不同。当您向每个模块添加print
语句时,您将在执行主脚本时看到以下内容:
加载魔法
加载imho
加载wtf
魔术内容:['__ builtin__','__ doc__','__ file __','_ _ 1 ___','__ package__','__ path __']
对于第二种情况:
加载魔法
加载wtf
加载imho
魔法内容:['__ builtin__','__ doc__','__ file __','_ _ 1 _','_ _ package__','__ path__','imho']
因此,在第一种情况下,{em> wtf.py 执行时已加载magic
和imho
,并且import
语句未重新加载已加载模块:
首先,如果模块已经存在于sys.modules中(如果在导入机制之外调用加载器的可能性)那么它将使用该模块进行初始化而不是新模块
如果您更改主脚本,例如:
if __name__ == '__main__':
here = os.path.dirname(os.path.realpath(__file__))
path = os.path.join(here, 'lib')
sys.path.append(path)
import magic.wtf
它与解释器完全相同。
如果您按照以下方式修改 wtf.py (为了演示目的),原始脚本也将按预期工作:
import sys
try:
del sys.modules['magic.imho']
except:
pass
import magic.imho
print "magic contents:", dir(magic)
或者像这样:
import sys
import magic.imho
magic.imho = sys.modules['magic.imho']
print "magic contents:", dir(magic)
输出:
加载魔法
加载imho
加载wtf
加载imho
魔法内容:['__ builtin__','__ doc__','__ file __','_ _ 1 _','_ _ package__','__ path__','imho']
注意:如果某个模块已加载,则sys.modules
中存在一个模块,该模块与导入不同。在第一种情况下,它是已加载,但未导入。因此它存在于sys.modules
中,但不存在于当前命名空间中。所以我猜它是由你的加载器加载而没有imho
绑定它(所以它只是裸magic
模块)。之后,当Python看到import magic.imho
时,它会检查magic
和magic.imho
是否已加载(可由print sys.modules
验证)并使用此版本的magic
并对其进行绑定到局部变量magic
。
相关: