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

写程序免不了需要加载不同的工具包或者自己写的其他程序文件,那么用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日常使用需要了解的机制了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值