import 导入
模块是 Python 组织代码的基本单元。一个 .py 文件就是一个模块,模块名就是文件名(不含 .py 后缀)。import 语句让当前程序可以使用其他模块中定义的函数、类和变量。
基本导入
import math
print math.pi # 3.14159265359
print math.sqrt(16) # 4.0
import math 导入整个 math 模块。使用时必须通过 math.name 访问模块中的内容。这种写法清晰明了:读者一眼就能看出 pi 和 sqrt 来自 math 模块。
从模块导入指定名称
from math import pi, sqrt
print pi # 3.14159265359
print sqrt(16) # 4.0
from math import pi, sqrt 只导入 pi 和 sqrt 两个名字,可以直接使用,无需前缀。适合频繁使用的名称,但牺牲了可读性——读者可能不知道 sqrt 来自哪里。
导入所有公开名称
from math import *
print pi
print sqrt(16)
print sin(0)
from module import * 导入模块中所有不以下划线开头的名称。这种写法方便但危险:
from os import * # 导入了 os.open
from math import * # 没有 open
open("file.txt") # 用的是 os.open 还是内置 open?
os.open 和内置 open 参数完全不同,混用会导致难以调试的 bug。PEP 8 明确反对 import *,除非在交互式解释器中快速试验。
别名导入
import numpy as np
from math import pi as PI
print np.array([1, 2, 3])
print PI
as 给导入的模块或名称起别名。这在以下场景很有用:
- 模块名太长(
numpy→np) - 避免名称冲突(
math.pi→PI) - 统一接口(不同平台导入不同实现,但用相同别名)
导入的执行过程
import 第一次导入模块时,会执行模块文件的全部代码:
# mymodule.py
print "Loading mymodule"
def hello():
print "Hello from mymodule"
# main.py
import mymodule # 输出:Loading mymodule
import mymodule # 无输出,已缓存
第二次 import mymodule 不会重新执行,而是从 sys.modules 缓存中直接获取已加载的模块对象。如果需要重新加载(如调试时修改了模块文件),用 reload():
import mymodule
reload(mymodule) # 重新执行模块代码
⚠️ reload() 是 Python 2 的内置函数,Python 3 中移到了 importlib 模块。
导入的搜索路径
Python 按以下顺序查找模块:
- 当前目录
PYTHONPATH环境变量中的目录- 标准库目录
- 第三方包目录(site-packages)
import sys
print sys.path # 查看搜索路径列表
sys.path 是一个列表,可以在运行时修改:
import sys
sys.path.insert(0, "/path/to/my/modules")
import mymodule
循环导入
两个模块互相导入会形成循环导入,可能导致问题:
# a.py
import b
def func_a():
b.func_b()
# b.py
import a
def func_b():
print "func_b"
当 a.py 被导入时,它开始执行 import b,b.py 开始执行 import a。此时 a 模块尚未完全初始化,b 中访问 a 的内容可能得到不完整的模块对象。
解决方法:
- 重构代码,消除循环依赖
- 把导入语句放到函数内部,延迟导入
- 合并两个模块
# b.py —— 延迟导入
def func_b():
import a # 在函数内部导入
a.func_a()
导入的命名空间
import 语句在当前命名空间中创建名称:
import math # 创建名称 "math",指向 math 模块
from math import pi # 创建名称 "pi",指向 math.pi
导入的名称可以像普通变量一样使用:
import math
alias = math # alias 也指向 math 模块
print alias.pi # 3.14159265359
del math # 删除名称 "math",但模块仍在内存中
print alias.pi # 仍然可以访问