Python 模块
Python 模块和包
Section titled “Python 模块和包”模块(Module)是组织 Python 代码的基本方式。它们允许你将相关的函数、类和变量分组到单独的文件中,从而提高代码的可重用性、可维护性和逻辑结构。模块本质上是一个包含 Python 定义和语句的 Python 文件(.py)。
可以将模块想象成工具箱。你不会把所有工具都分散在各处,而是将相关工具(例如扳手或螺丝刀)分组到特定的工具箱中。当你需要某个特定工具时,你会拿起正确的工具箱(导入模块),然后从中取出你需要的工具。
示例:创建一个简单模块
Section titled “示例:创建一个简单模块”让我们创建一个名为 helpers.py 的模块:
"""A simple module with helper functions."""
PI = 3.14159
def greet(name): """Greets the person with the given name.""" print(f"Hello, {name}!")
class Calculator: """A basic calculator class.""" def add(self, x, y): return x + yimport 语句
Section titled “import 语句”要在另一个 Python 文件(例如 main.py)中使用模块中的定义,可以使用 import 语句。基本语法是:
import module_name# 或者导入多个模块import module1, module2# 或者更推荐的风格(每行一个 import)import module_oneimport module_two当 Python 遇到 import helpers 时,它会在其搜索路径中查找 helpers.py(或其他模块类型)。找到后,它会执行模块的代码(如果尚未导入),并通过模块名作为前缀来提供其定义。
示例(main.py 与 helpers.py 在同一目录下):
import helpers
helpers.greet("Alice")print(f"The value of PI is approximately: {helpers.PI}")
calc = helpers.Calculator()result = calc.add(5, 3)print(f"5 + 3 = {result}")运行 python main.py 会产生:
Hello, Alice!The value of PI is approximately: 3.141595 + 3 = 8模块在程序执行期间只加载和执行一次,即首次导入时。后续导入同一个模块只会检索已加载的模块对象。
from...import 语句
Section titled “from...import 语句”此语句允许将特定名称(函数、类、变量)直接导入到当前脚本的命名空间中,从而无需使用模块前缀。
from module_name import name1# 或者导入多个名称from module_name import name1, name2# 或者导入并重命名from module_name import name1 as alias_name示例:
from helpers import greet, PIfrom helpers import Calculator as Calc # 重命名
greet("Bob")print(f"PI: {PI}")
my_calc = Calc()print(f"10 + 5 = {my_calc.add(10, 5)}")这样做避免了使用 helpers. 前缀,但将导入的名称直接引入了当前作用域。请注意潜在的名称冲突。
from...import * 语句
Section titled “from...import * 语句”你可以使用以下语句从模块中导入所有公共名称(即不以下划线 _ 开头的名称):
from module_name import *警告: 在生产代码中通常不建议使用这种做法。它可能将许多名称导入当前命名空间,导致难以确定特定名称的来源,并增加名称冲突的风险。在交互式会话中或者有时在特定模块模式(如 __init__.py)中是可接受的。
模块搜索路径
Section titled “模块搜索路径”当你 import my_module 时,Python 会按以下顺序查找它:
- 包含输入脚本的目录(如果在交互模式下,则为当前目录)。
PYTHONPATH环境变量中列出的目录(如果已设置)。格式取决于平台(例如,在 Unix/macOS 上以冒号分隔,在 Windows 上以分号分隔)。- 安装相关的默认路径(通常在 Python 安装目录的
site-packages子目录中)。
搜索路径可以通过 sys.path 程序化访问,它是一个字符串列表。
import sysprint(sys.path)PYTHONPATH 变量
Section titled “PYTHONPATH 变量”PYTHONPATH 是一个环境变量,你可以设置它来添加 Python 查找模块的额外目录。其语法类似于系统的 PATH 变量。
示例 (Linux/macOS):
export PYTHONPATH="/home/user/my_python_libs:/another/path"示例 (Windows 命令提示符):
set PYTHONPATH=C:\Users\user\my_python_libs;D:\other_path虽然 PYTHONPATH 可能有用,但使用虚拟环境(virtual environments)和标准包安装工具(pip)来管理依赖关系是现代推荐的方法。
命名空间和作用域
Section titled “命名空间和作用域”命名空间(Namespace)是从名称到对象的映射(类似于字典)。Python 使用命名空间来避免名称冲突。
Python 遵循 LEGB 规则进行作用域解析:局部(Local)-> 外部(Enclosing)函数局部 -> 全局(Global) -> 内置(Built-in)。
要在函数内部修改全局变量,必须使用 global 关键字。要在外部函数作用域(在嵌套函数中)修改变量,使用 nonlocal 关键字(Python 3+)。
x = 100 # 全局变量
def outer_func(): y = 20 # 外部(封闭)局部变量 def inner_func(): nonlocal y # 修改外部作用域变量 global x # 声明要修改全局变量 z = 5 # 局部变量 y += 5 x += 1 print(f"Inner: x={x}, y={y}, z={z}") inner_func() print(f"Outer: x={x}, y={y}")
outer_func()print(f"Global: x={x}")dir() 函数
Section titled “dir() 函数”内置函数 dir() 在没有参数调用时,返回当前局部作用域中的名称列表。当以对象(例如模块)作为参数调用时,它返回该对象定义的名称(其属性、方法等)的排序列表。
import math
print(dir(math)) # 列出 math 模块中的名称
my_var = 10def my_func(): passprint(dir()) # 列出当前(全局)作用域中的名称输出可能包含一些特殊名称,如 __name__(模块名称)和 __file__(模块文件路径)。
globals() 和 locals() 函数
Section titled “globals() 和 locals() 函数”这些内置函数分别返回表示全局和局部命名空间的字典。
重新加载模块(importlib.reload)
Section titled “重新加载模块(importlib.reload)”模块通常只加载一次。如果你的主程序正在运行期间修改了模块的源代码文件(在交互式开发或长时间运行的应用程序中很常见),更改不会自动反映。要强制重新加载已导入的模块,请使用 importlib.reload() 函数(注意:reload 在 Python 2 中是内置函数,但在 Python 3 中移至 importlib)。
import importlibimport helpers
# ... 使用 helpers 的代码 ...
# 假设 helpers.py 被修改了importlib.reload(helpers)
# 现在使用更新版本的 helpershelpers.greet("Updated User")请谨慎使用 reload,如果管理不当,它可能导致不一致,尤其是在处理复杂依赖关系或有状态对象时。
Python 中的包
Section titled “Python 中的包”包(Package)提供了一种使用“点分模块名”来组织 Python 模块命名空间的方式。包本质上是一个包含 Python 模块以及可能的其他子包的目录。要被识别为常规包(在 Python 3.3 之前,至今仍是常见做法),该目录必须包含一个名为 __init__.py 的文件(该文件可以为空)。
示例结构:
sound/ __init__.py formats/ __init__.py wavread.py aiffread.py ... effects/ __init__.py echo.py surround.py ... filters/ __init__.py equalizer.py ...你可以使用点号表示法从包中导入模块:
import sound.effects.echosound.effects.echo.apply_echo(...)
from sound.formats import wavreadwavread.read_wavfile(...)
from sound.filters.equalizer import Equalizereq = Equalizer()__init__.py 文件
Section titled “__init__.py 文件”__init__.py 文件有几个用途:
示例(sound/effects/__init__.py):
print("正在初始化 sound effects 包...")
# 使 echo 和 surround 可以通过 'from sound.effects import ...' 直接访问from . import echofrom . import surround
# 控制 'from sound.effects import *' 导入的内容__all__ = ["echo", "surround"]有了这个 __init__.py 文件,你可以这样做:
import sound.effects
sound.effects.echo.apply_echo(...) # 通过子模块访问注意:Python 3.3 引入了隐式命名空间包(Implicit Namespace Packages,PEP 420),允许在没有 __init__.py 文件的情况下创建包,这主要用于将一个大型包拆分到多个目录中。