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