关于Python中的import(三)

来源:互联网 发布:网络用语ps是什么意思 编辑:程序博客网 时间:2024/06/08 12:18

上节介绍了 importlib.import_module(),和 package 的基础概念,本节深入理解导模块的机理以及简单了解 Namespace package

在 import 模块的时候,系统会首先到 sys.modules 里面去查找要导入的模块,sys.modules 是个什么东东呢,我们打印一下看看它是什么:

import sysprint(type(sys.modules))  # <class 'dict'>

sys.modules 是一个存放缓存模块的字典,打印一下会发现许多条目所有之前导入过的模块都在这个字典中。当我们导入一个模块时,会首先查看 sys.modules里面有没有缓存,如果有直接返回,搜索过程结束;如果没有,则继续查找。

例如导入模块 foo.bar.biz, 系统会首先导入中间模块 foo,然后是 foo.bar,最后是 foo.bar.biz, 然后 sys.modules 中会多出三条条目,键分别为 “foo”、“foo.bar”、“foo.bar.biz”,值为对应的模块对象,多次导入会拿到同一个模块对象,并且第一次导入模块时会执行模块内的代码。

假如在 sys.modules 中没有找到要导入的模块,那么系统就要进一步搜索模块,这里有很多具体细节,就不说了,总的来说就是如果是我们自己定义的模块,会往 sys.path 中去找

import sysprint(sys.path)

打印出的结果是一个列表,列表里面是一些路径,默认状态下第一个路径是我们启动 python 程序的工作目录,首先在这个目录下查找模块。例如导入 foo.bar.biz, 会首先在 sys.path 下寻找 foo 模块,找到后,再在 foo 的 __path__ 下查找bar, 再在 bar 的 __path__ 下查找 biz。

而 sys.path 是可以修改的,我们可以向里面 insert 搜索路径。

parent/    main.py    one/        __init__.py        mymodule.py    two/        __init__.py    three/        __init__.py

假设我们通过执行 main.py 启动 Python 程序,parent 为工作目录,这时需要在 main 模块中导入 mymodule 模块,需要 import one.mymodule, 假如在导入之前,执行 sys.path.append(‘./one’)

import syssys.path.append('./one')import mymodule

这样就会直接在 parent/one/ 路径下查找到模块,但是注意这样创建的模块和通过 import one.mymodule 方式导入的模块不是同一个对象,在 sys.modules 中会对应两个不同的键值对。

Namespace package

Namespace package 与 Regular package 表面上的不同点是 Namespace package 下没有 __init__.py 文件, 还是用实例来说明

Lib/test/namespace_pkgs    project1        parent            child                one.py    project2        parent            child                two.py

这里两个 parent 和 两个 child package下都没有 __init__.py 文件,

>>> import sys>>> sys.path += ['Lib/test/namespace_pkgs/project1', 'Lib/test/namespace_pkgs/project2']>>> import parent.child.one>>> parent.__path___NamespacePath(['Lib/test/namespace_pkgs/project1/parent', 'Lib/test/namespace_pkgs/project2/parent'])>>> parent.child.__path___NamespacePath(['Lib/test/namespace_pkgs/project1/parent/child', 'Lib/test/namespace_pkgs/project2/parent/child'])>>> import parent.child.two>>>

每个 namespace package 的 __path__ 属性,都有两条。说白了此时就是通过 import parent.child.xxx.py 导入模块时,有两条可搜索的路径,在 sys.path += [‘Lib/test/namespace_pkgs/project1’, ‘Lib/test/namespace_pkgs/project2’] 执行后,sys.path中就多了两条搜索路径,这两条搜索路径下有相同的 namespace package 结构,于是乎就发生了些不可描述的事情,大家自行体会。namespace package 的 __path__ 我们是不能去修改的,系统会自动动态更新。

import 的内容就简单说到这,关于 import 还有些更深入的内容,就暂时不去探究了,以后如果遇到再来补充。


参老资料:
官方文档 3.6.2
https://www.python.org/dev/peps/pep-0420/