您的位置:首页 > 编程语言 > Python开发

关于Python的import机制你了解透了吗?

2018-02-09 15:26 162 查看
写程序免不了需要加载不同的工具包或者自己写的其他程序文件,那么用Python写程序,你就逃不掉跟import打交道,如果你不了解import的机制,就很容易产生一些bug。
首先说一下import的流程,当你import一个module的时候,import组件就会在sys.modules里面搜索是否有这个module,如果有,直接返回module object。如果没有这个key,那么finder就开始从内置模块、编译好的模块、系统路径、已经存在的package的path里面找,当找到了这个模块,loader就执行加载操作(运行module里执行的代码)。注意,在执行加载操作之前,通常会现在sys.module里面加入当前import的module,这样做是为了避免发生import的死循环。
Python有一种特殊的module叫做package:kionwong/
__init__.py
one/
__init__.py
two/
__init__.py
three/
__init__.py
那么我们import kionwong的时候,加载模块只会执行__init__.py,当我们加载import kionwong.one的时候,加载模块则会执行__init__.py和one/__init__.py:In [1]: import kionwong.one
init kionwong
init one

In [2]: import sys

In [3]: 'kionwong' in sys.modules
Out[3]: True

In [4]: 'one' in sys.modules
Out[4]: False

In [5]: 'kionwong.one' in sys.modules
Out[5]: True

In [6]: kionwong
Out[6]: <module 'kionwong' from 'C:\\ProgramData\\Anaconda2\\envs\\py3\\lib\\sit
e-packages\\kionwong\\__init__.py'>

In [7]: one
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-7-5bbf5a52328e> in <module>()
----> 1 one

NameError: name 'one' is not defined

In [8]: kionwong.one
Out[8]: <module 'kionwong.one' from 'C:\\ProgramData\\Anaconda2\\envs\\py3\\lib\
\site-packages\\kionwong\\one\\__init__.py'>
one的时候,系统首先看看sys.modules里面有没有kionwong,发现没有,那么就先import kionwong,执行了__init__.py输出“init kionwong”。然后执行import kionwong.one,系统就会在kionwong的path里面查找到one,然后执行one/__init__.py输出“init one”。这时候我们可以看到modules里面是有'kionwong'、'kionwong.one'。最后我们依次输入kionwong、one、kionwong.one会发现,我们可以直接调用kionwong和kionwong.one。
那么如果使用from kionwong import one 会怎样呢?In [1]: from kionwong import one
init kionwong
init one

In [2]: import sys

In [3]: 'kionwong' in sys.modules
Out[3]: True

In [4]: 'one' in sys.modules
Out[4]: False

In [5]: 'kionwong.one' in sys.modules
Out[5]: True

In [6]: kionwong
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-6-f91d0986c070> in <module>()
----> 1 kionwong

NameError: name 'kionwong' is not defined

In [7]: one
Out[7]: <module 'kionwong.one' from 'C:\\ProgramData\\Anaconda2\\envs\\py3\\lib\
\site-packages\\kionwong\\one\\__init__.py'>

In [8]: kionwong.one
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-8-5d3efa07b17f> in <module>()
----> 1 kionwong.one

NameError: name 'kionwong' is not defined我们发现,from kionwong import one的时候,执行的文件以及sys.modules里的key跟import kionwong.one是一样的,但区别在于,这种情况我们只能调用one这个对象,其他都无法直接调用了。
从这个对比也能看出,模块装载和返回模块对象是两码事,同时使用的名字跟模块在系统字典里存的名字也是两码事。这样也说明了为什么一直不提倡使用from import,当两个不同的模块同时有重名的子模块的时候,你很可能就会产生混乱了。
还有一件事情,当我们import numpy的时候,我们可以使用numpy.random,但我们import selenium的时候,并不能使用selenium.webdriber,这是为什么呢?关键就是在__init__.py上,一般来说,在装载包的时候,默认只会执行__init__.py文件,当这个文件里面是空的时候,那么这个包跟个普通的文件夹没什么区别,比如selenium/__init__.py。但我们可以看看numpy/__init__.py这个文件,里面还写入了怎么加载子模块的语句,当完成这个文件的时候,子模块也被加载了,我们便可以在不自己加载子模块的时候也能使用了。
当我们使用from import*会怎样呢?In [1]: from kionwong import *
init kionwong我们可以看到依然只会执行kionwong下的__init__.py。
当然,如果你只是import一个具体文件,也就没有那么多事了,只需要记得import后面不能跟具体的类和函数,只能通过from import去加载类和函数,虽然不建议这样做。
最后一个就是别名了,当我们import numpy as np的时候:In [9]: import numpy as np

In [10]: 'np' in sys.modules
Out[10]: False

In [11]: 'numpy' in sys.modules
Out[11]: True我们可以知道,numpy依然是存在sys.modules里面的名字。
以上基本就是关于import日常使用需要了解的机制了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  import Python module