我正在研究python如何加载模块。
我从requests
开始加载urllib3
。
我找到了those line:
from .packages.six.moves.http_client import (
IncompleteRead as httplib_IncompleteRead
)
名为src/urllib3/exceptions.py
的文件
该导入是一个相对的导入,因此我正在寻找文件夹src/urllib3/packages/six/moves/http_client.py
或src/urllib3/packages/six/moves/http_client/__init__.py
这些文件不存在。
感谢src/urllib3/packages/six.py
定义了一个新的模块加载器,因此导入.packages.six.moves.http_client
要求使用http_client
核心python模块。
但是我不知道src/urllib3/packages/six.py
是如何加载的。
我没有找到这种导入。
有没有办法知道哪个模块直接加载src/urllib3/packages/six.py
?
我尝试使用__name__
全局变量,如建议的here所示。其值为urllib3.packages.six
,但urllib3.packages
不会加载该文件。
答案 0 :(得分:3)
from .packages.six.moves.http_client import ...
表达式导致.packages.six
首先被加载。 Python始终将所有程序包加载到模块的嵌套程序包引用中。
因此,.packages.six.moves.http_client
使Python首先寻找urllib3.packages
,然后寻找urllib3.packages.six
,依此类推。导入机制通过在sys.modules
中查找全名来实现,如果不存在全名,则会触发模块搜索并为每个模块加载。
第一次出现这种情况,sys.modules['urllib3.packages.six']
尚不存在,导入机制会找到文件urllib3/packages/six.py
,并在之前导入,它将寻找更多名称
而且,正如您所发现的那样,导入six.py
模块文件的行为使该模块添加了sys.modules['urllib3.packages.six.moves']
并进一步引用了标准库模块。
Python的导入机制相当复杂。 Python参考文档在The import system中对此进行了全面介绍;要查找的特定条目是:
直接调用
__import__()
仅执行模块搜索,如果找到,则执行模块创建操作。尽管可能会发生某些副作用,例如,例如,导入父包,以及更新各种缓存(包括sys.modules),但只有import语句执行名称绑定操作。
导入
parent.one
将隐式执行parent/__init__.py
和parent/one/__init__.py.
,随后导入parent.two
或parent.three
将执行parent/two/__init__.py
和parent/three/__init__.py
分别。
在导入搜索期间检查的第一位是
sys.modules
。此映射充当所有先前导入的模块的缓存,包括中间路径。因此,如果先前导入了foo.bar.baz
,则sys.modules
将包含foo
,foo.bar
和foo.bar.baz
的条目。每个键都有对应的模块对象作为其值。
(我在加引号的部分中大胆强调)。
请注意,urllib3/packages
目录中的所有内容都是 vendorized 包;通常可以独立安装的项目,但是urllib3
项目已决定将其与自己的发行版打包在一起,从而不必担心要支持哪些版本。 six
是一个独立的项目,您可以安装from PyPI。
您可以在six.moves
virtual package的six
project documentation中找到更多信息。目的是使库开发人员更轻松地编写与Python 2和Python 3兼容的代码,而不必担心在任何一个版本上导入哪个标准库名称。
答案 1 :(得分:0)
关于Python中的导入函数的一个值得注意的事情是,它不仅可以导入模块本身,还可以从模块内部导入变量,类,函数(通常是名称空间)。 在示例中,您提供了:
from .packages.six.moves.http_client import (
IncompleteRead as httplib_IncompleteRead
)
import语句引用src/urllib3/packages/six.py
模块中的 moves 变量,该变量在该文件的第316行定义,并分配给类 _MovedItems 的实例:
moves = _MovedItems(__name__ + ".moves")
和 http_client 是此类实例的属性或方法