使用自定义加载函数时,模块中未定义Python模块

本教程将介绍使用自定义加载函数时,模块中未定义Python模块的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

使用自定义加载函数时,模块中未定义Python模块 教程 第1张

问题描述

考虑使用以下程序加载目录中的所有模块:

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/magic/imho.py:

"""This is an empty module.
"""

lib/Magic/wtf.py:

import magic.imho
print "magic contents:", dir(magic)

lib/magic/__init__.py:

"Empty package init file"

执行上述程序时,输出:

magic contents: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']

换句话说,尽管import magic.imhoimho上没有导致以后引用magic.imho失败的属性。

直接在python中运行相同的代码(或多或少)会显示不同的输出,这是我在运行加载程序时预期的输出。

$ 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']

为什么会有差异?

更新:这里的要点是magic.imho中不存在符号magic.wft,尽管它是显式导入的。因此,需要对自定义加载过程执行哪些操作才能使其正常运行,并确保将在magic内部正确绑定名称。因此,下一次导入magic时,它将不会被重新加载(因为此函数已经将其放入sys.modules中),但它将正确地分配其所有子模块。

这似乎缓解了import机制中的一些问题,我在下面尝试对其进行诊断。


差异实际上来自于这样一个事实:在第一种情况下,模块的加载顺序与在第二种情况下不同。当请问print语句添加到每个模块时,请问在执行主脚本时看到以下内容:

加载魔术

正在加载imho

正在加载wtf

魔术内容:[‘__内建__’,‘__文档__’,‘__文件__’,‘__名称__’,‘__包__’,‘__路径__’]

对于第二种情况:

加载魔术

正在加载wtf

正在加载imho

魔术内容:[‘__内建__’,‘__文档__’,‘__文件__’,‘__名称__’,‘__包__’,‘__路径__’,‘imho’]

因此,在第一种情况下,<wtf.py执行时magicimho已经加载,并且import语句不重新加载已经加载的模块:

首先,如果模块已经存在于系统模块中(如果在导入机器外部调用加载程序,则有可能),则它将使用该模块进行初始化,而不是使用新模块

如果您像这样更改主脚本,例如:

if __name__ == '__main__':
 here = os.path.dirname(os.path.realpath(__file__))
 path = os.path.join(here, 'lib')
 sys.path.append(path)
 import magic.wtf

它与解释器的工作方式完全相同。

如果您修改(出于演示目的),您的原始脚本也将按预期工作:

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

魔术内容:[‘__内建__’,‘__文档__’,‘__文件__’,‘__名称__’,‘__包__’,‘__路径__’,‘imho’]

注意:如果且不同于,则sys.modules中存在模块。在第一种情况下,,但未导入。因此它存在于sys.modules中,但不存在于当前命名空间中。所以我猜它是由您的加载器加载的,没有绑定imho(所以它只是magic模块)。然后,当Python看到import magic.imho时,它会检查magicmagic.imho是否已经加载(可以通过print sys.modules进行验证),并获取这个版本的magic并将其绑定到局部变量magic


相关:

    Realoading Python modules

    Traps for the Unwary in Python’s Import System(不应将本地包添加到sys.path)

    Prevent Python from caching the imported modules

好了关于使用自定义加载函数时,模块中未定义Python模块的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。