一、什么是模块?
模块是一个包含 Python 定义和语句的 .py 文件。模块名就是文件名(去掉 .py 后缀)。通过模块,你可以将相关的函数、类和变量组织在一起,供其他程序导入和使用。
例如:mymodule.py 就是一个模块,文件名 mymodule 就是模块名。
二、使用模块的优势
- 代码重用:写好的功能可以在多个程序中直接导入,避免重复编写。
- 命名空间管理:模块提供了独立的命名空间,避免全局变量、函数名冲突。
- 可维护性:把相关功能放在一个模块里,代码结构清晰,便于定位和修改。
- 封装与抽象:模块可以隐藏内部实现细节,只暴露需要的接口(通过
__all__ 或命名约定 _ 开头的“私有”成员)。 - 分步编译:导入时生成的
.pyc 字节码文件能略微提升加载速度。
三、模块的使用与注意事项
1. 导入方式
import module_name:导入整个模块,使用时需要 module_name.func()。from module_name import name1, name2:导入特定成员,直接使用名称。from module_name import *:导入所有公开成员(不推荐,容易命名冲突)。import module_name as alias:起别名,简化长名称。
2. 模块搜索路径
Python 按以下顺序查找模块:
- 第三方库安装路径(如
site-packages)
查看完整搜索路径:import sys; print(sys.path)。
注意:不要将自己的模块文件命名为标准库或第三方库的名字(如 sys.py、datetime.py),否则会屏蔽原来的模块。
3. 模块重复导入
模块在同一个进程中只会被导入一次,即使有多个 import 语句。再次导入只是引用已加载的模块对象。如果需要重新加载(调试时),可以用 import importlib; importlib.reload(module)。
4. 避免循环导入
A 模块导入 B,B 又导入 A,会导致部分属性未定义。解决方法:
5. if __name__ == "__main__" 保护
这是模块使用中最核心的。每个模块都应该包含这个条件块,用于区分“作为主程序直接运行”和“被其他模块导入”两种情况。
四、__name__ 与 __main__ 详解
每个 Python 模块都有一个内置属性 __name__:
- 当模块被直接运行时(如
python script.py),__name__ 被赋值为 "__main__"。 - 当模块被导入时(如
import script),__name__ 被赋值为模块名(即文件名去掉 .py)。
1. 典型用法:可复用的模块同时包含测试或入口代码
# example.py
defadd(a, b):
return a + b
defmain():
print("测试加法:", add(3, 5))
if __name__ == "__main__":
main()
- 直接运行:
python example.py → 输出 测试加法: 8 - 被导入:
import example → 不会自动执行 main(),但 add 函数可以被其他代码使用。
2. 在普通 Python 程序中(作为主程序)
普通程序(脚本)通常没有设计为供他人导入,所以可以不写 if __name__ == "__main__" 块,全部代码都会在运行时顺序执行。但养成良好的习惯仍然建议加上,因为以后你可能想要导入其中的函数。
示例:主程序特有的行为
- 直接运行时会解析命令行参数、执行核心逻辑、输出结果。
- 作为模块导入时只提供函数/类定义,不执行任何副作用操作(如文件写入、网络请求)。
3. 模块中 __main__ 的差异总结
| __name__ | |
|---|
| "__main__" | if __name__ == "__main__" |
| | |
4. 进阶:__main__.py 文件
当你有一个包(目录包含 __init__.py),并希望它能被直接运行(python -m mypackage),可以在包内放置 __main__.py 文件。此时 __main__.py 中的 __name__ 也会是 "__main__",作为整个包的入口脚本。
五、完整示例对比
假设文件 utils.py:
# utils.py
print("模块被加载了,__name__ =", __name__)
defgreet(name):
returnf"Hello, {name}"
if __name__ == "__main__":
print("这是直接运行 utils.py 的效果")
print(greet("World"))
情况1:直接运行
$ python utils.py
模块被加载了,__name__ = __main__
这是直接运行 utils.py 的效果
Hello, World
情况2:被导入
# main.py
import utils
print(utils.greet("Alice"))
运行 main.py:
模块被加载了,__name__ = utils
Hello, Alice
注意:直接运行时的提示语 “这是直接运行...” 没有被打印,因为 __name__ 不等于 "__main__"。
六、最佳实践
- 始终在模块底部使用
if __name__ == "__main__": 来编写测试代码或命令行入口。 - 不要在模块顶层执行有副作用的操作(如打开文件、连接数据库),除非这些操作是模块初始化所必需且无其他替代方案。
- 使用
if __name__ == "__main__" 块调用一个 main() 函数,这样可以在需要时直接从其他模块调用 main()。 - 为模块添加文档字符串(docstring),说明模块的用途和公开接口。
- 避免
from module import *,它会污染命名空间,并且无法明确导入了哪些名称。可以显式列出 __all__ 来控制 import * 的行为。
通过合理使用模块和 __main__ 保护,你可以写出既可作为独立脚本运行、又可被他人复用的高质量 Python 代码。
PS:AI配图有点low啊,凑数用的。