import做了什么
- 在
sys.modules
中寻找该模块是否之前被引入过,如果有,引入该名字[import mode
相当于mod = sys.modules['mod']
] - 如果没有:
- 在
sys.path
中寻找该模块,如果没找到,报错 - 如果找到,创建一个空的模块对象,通常为
dict()
- 将该模块写入
sys.modules
- 加载该模块文件(如果有必要,先编译)
- 执行该模块代码,
def
,import
,class
实际上都是表达式,执行之后才可以被访问
- 在
形式
from mod import *
'''
for all public_name in mod:
sys.modules[public_name] = public_name的定义
'''
备注:
- 只能出现在模块作用域
- mod本身没有被引入,因此mod.name会报错
- 会寻找该模块定义的公共名字(public names),如果有
__all__
的定义,那么该变量定义的名字均为公共的,否则该模块中不以_
开头的名字将被视为公共名字
import X
'''
sys.modules['X'] = X的定义
'''
备注:
- 只能引入包或模块,不能引入模块内定义的类、函数或变量
- 如果X是包,会执行init.py,如果里面有import,则会在sys.modules加入引入的模块
from mod import foo
'''
foo 可以为包、模块、类、函数、变量
submodules['mod'] = mod的定义
submodules['mod.foo'] = mod.foo的定义
'''
最佳实践
- 不要使用
from module import *
- 在文件的开始处
import
所需的模块 - 以下列顺序
import
不同的模块:- 系统库的模块,如
os
,sys
等; - 第三方的模块
- 当前工程自定义的模块
- 系统库的模块,如
- 不使用相对路径的
import
,永远使用绝对路径import
参考PEP328 - 可以在函数内
import
,比如平台相关的代码,或者降低模块初始化的耗时 - 如果某个类的对象需要使用某个模块,可以在
__init__(self)
中import
该模块并且赋值为该类对象的一个成员变量,这样该模块在对象整个生命周期都是可用的,但一定要写在函数内,如果没有,那么实际上该模块的初始化是发生在该类所属模块的初始化阶段;
PEP328
- 永远使用绝对路径
import
,让所有的模块都从sys.path
中寻找,避免出现语义混淆:import item
:不清楚是相对于当前模块的其他模块,还是某个package
- 如果从一个模块或包中引入很多名字,那么使用
()
括起来:from package import (m1, m2, m3 m4, m5, m6)
- 如果使用相对引用,那么只能使用
from <> import mod
,如果使用import mod
,那么被认为是绝对引用
例子
# 文件结构:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
main.py
访问包的模块
# main.py
'''
如果package目录下的__init__.py中没有import moduleA,
下面这个语句会报错: 'module' object has no attribute 'moduleA'
原因是默认不会import一个包所包含的模块
'''
import package
print package.moduleA.foo
'''
推荐写法如下
'''
import package.moduleA as modA
print modA.foo
# 或
from package import moduleA
print moduleA.foo
相对路径引用
同一package的module相互引用
# moduleX.py
from . import moduleY
from .moduleY import spam as ham
from ..subpackage1 import moduleY
引用不同package的module
# moduleX.py
from ..subpackage2 import moduleZ
from ..moduleA import foo
from ...package import bar