Python 模块:组织代码以提升清晰度与复用性
模块让你能够逻辑清晰地组织 Python 代码。将相关代码归入一个模块,能使代码更易理解、更易使用。模块本质上是一个拥有任意命名属性的 Python 对象,你可以绑定和引用这些属性。
简单来说,模块就是一个包含 Python 代码的文件。模块可以定义函数、类和变量,也可以包含可直接运行的代码。
示例
名为 aname 的模块,其代码通常位于名为 aname.py 的文件中。下面是一个简单的模块示例 support.py:
def print_func(par):
print("Hello : ", par)
return
import 语句
你可以通过在另一个 Python 源文件中执行 import 语句,将任意 Python 源文件作为模块使用。import 语法如下:
import module1[, module2[,... moduleN]]
当解释器遇到 import 语句时,如果模块位于搜索路径中,就会导入该模块。搜索路径是解释器在导入模块前会搜索的目录列表。例如,要导入 support.py,需在脚本顶部添加以下命令:
#!/usr/bin/python
# 导入模块 support
import support
# 现在可以调用模块中定义的函数
support.print_func("Zara")
执行上述代码,输出结果为:
Hello : Zara
无论导入多少次,模块只会被加载一次。这防止了多次导入时模块代码重复执行。
from...import 语句
Python 的 from 语句允许你从模块中导入特定属性到当前命名空间。语法如下:
from modname import name1[, name2[, ... nameN]]
例如,从模块 fib 导入函数 fibonacci:
from fib import fibonacci
该语句不会将整个 fib 模块导入当前命名空间,而只是将模块中的 fibonacci 引入到导入模块的全局符号表中。
from...import * 语句
也可以使用以下语句将模块中的所有名称导入当前命名空间:
from modname import *
这提供了一种便捷的方式一次性导入模块中的所有项目,但应谨慎使用,避免命名冲突。
模块搜索路径
导入模块时,Python 解释器按以下顺序搜索:
- 当前目录。
- 如果未找到,则搜索环境变量
PYTHONPATH中的每个目录。 - 如果仍未找到,则检查默认路径。在 UNIX 上,默认路径通常为
/usr/local/lib/python/。
模块搜索路径存储在 sys 模块的 sys.path 变量中。sys.path 包含当前目录、PYTHONPATH 以及安装相关的默认路径。
PYTHONPATH 环境变量
PYTHONPATH 是一个环境变量,由目录列表组成,语法与 Shell 变量 PATH 相同。
Windows 系统典型设置:
set PYTHONPATH = c:\python20\lib;
UNIX 系统典型设置:
set PYTHONPATH = /usr/local/lib/python
命名空间与作用域
变量是映射到对象的名称(标识符)。命名空间是变量名(键)及其对应对象(值)的字典。
Python 语句可以访问局部命名空间和全局命名空间中的变量。若局部变量与全局变量同名,局部变量会遮蔽全局变量。
每个函数都有自己的局部命名空间。类方法遵循与普通函数相同的作用域规则。
Python 会根据变量在函数中是否被赋值,推断其为局部或全局变量。假设变量在函数中被赋值,则视为局部变量。
因此,要在函数内给全局变量赋值,必须先使用 global 语句声明。
global VarName 告诉 Python VarName 是全局变量,Python 将不再在局部命名空间中查找该变量。
例如,在全局命名空间定义变量 Money。在函数 AddMoney 中对 Money 赋值,Python 会将其视为局部变量。但我们在赋值前访问了局部变量 Money,导致 UnboundLocalError。取消注释 global 语句即可解决。
#!/usr/bin/python
Money = 2000
def AddMoney():
# 取消下面注释以修复代码:
# global Money
Money = Money + 1
print(Money)
AddMoney()
print(Money)
dir() 函数
内置函数 dir() 返回一个排序后的字符串列表,包含模块定义的所有名称。
列表包含模块中定义的所有模块、变量和函数名。示例如下:
#!/usr/bin/python
# 导入内置模块 math
import math
content = dir(math)
print(content)
执行结果:
['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
其中,特殊字符串变量 __name__ 是模块名,__file__ 是加载模块的文件名。
globals() 与 locals() 函数
globals() 和 locals() 函数根据调用位置,返回全局和局部命名空间中的名称。
- 在函数内调用
locals(),返回该函数可局部访问的所有名称。 - 在函数内调用
globals(),返回该函数可全局访问的所有名称。
两者返回类型均为字典,可使用 keys() 提取名称。
reload() 函数
模块被导入脚本时,模块顶层代码仅执行一次。若需重新执行模块顶层代码,可使用 reload() 函数。该函数再次导入已导入的模块。语法:
reload(module_name)
此处 module_name 是模块对象名,而非字符串。例如重新加载 hello 模块:
reload(hello)
Python 包
包是一种分层的文件目录结构,定义了一个由模块、子包及子子包组成的 Python 应用环境。
假设 Phone 目录下有 Pots.py 文件,内容如下:
#!/usr/bin/python
def Pots():
print("I'm Pots Phone")
同理,还有两个文件分别包含同名函数:
Phone/Isdn.py包含函数Isdn()Phone/G3.py包含函数G3()
在 Phone 目录下创建 __init__.py 文件。为使导入 Phone 时所有函数可用,需在 __init__.py 中显式导入:
from Pots import Pots
from Isdn import Isdn
from G3 import G3
添加上述内容后,导入 Phone 包即可使用所有类:
#!/usr/bin/python
# 导入 Phone 包
import Phone
Phone.Pots()
Phone.Isdn()
Phone.G3()
执行结果:
I'm Pots Phone
I'm 3G Phone
I'm ISDN Phone
以上示例每个文件仅含一个函数,实际可包含多个函数,也可定义类,再从这些类创建包。
Python