7.9 KiB
doc_type, full_text
| doc_type | full_text |
|---|---|
| short | sources/05_Main_module.md |
05_Main_module 总结
本文介绍 Python 中“主程序/主模块”的概念,以及如何把模块组织成可导入、可执行的命令行脚本。核心主题包括 __name__ == '__main__' 惯用法、main() 程序模板、命令行参数、标准输入输出、环境变量、程序退出和 Unix #! 脚本启动方式。
主函数与 Python 主模块
许多语言有显式的主函数,例如 C/C++ 的 int main(...) 或 Java 的 public static void main(...)。它们是程序启动后首先执行的入口。
Python 没有固定的 main 函数或方法,而是有“主模块”(main module):
- 启动解释器时传入的源文件就是主模块。
- 文件名不重要,谁被解释器首先执行,谁就是主模块。
- 例如:
python3 prog.py中,prog.py就是主模块。
相关概念可扩展为 Python模块与导入机制、Python程序入口。
__main__ 检查
Python 脚本中常见的入口保护写法是:
if __name__ == '__main__':
statements
含义:
- 当文件作为主程序运行时,
__name__被设置为'__main__'。 - 当文件被
import导入时,__name__通常是模块名,不会等于'__main__'。 - 因此,放在该条件块中的代码只会在脚本直接运行时执行,不会在被导入时自动执行。
这种写法使一个 Python 文件既可以作为脚本运行,也可以作为库模块被导入。
主程序与库导入
同一个 Python 文件可以有两种使用方式:
python3 prog.py
表示作为主程序运行。
import prog
表示作为库导入。
通常不希望“主程序逻辑”在导入时自动执行,因为导入模块时往往只是想使用其中的函数、类或变量。因此,模块中可执行的测试、命令行处理、打印输出等逻辑应放入:
if __name__ == '__main__':
...
这体现了 Python 模块设计中的一个重要原则:将可复用逻辑与命令行入口分离。相关主题可归入 Python脚本与库的双重用途。
常见程序模板
一个典型 Python 程序结构如下:
# prog.py
import modules
# Functions
def spam():
...
def blah():
...
# Main function
def main():
...
if __name__ == '__main__':
main()
该模板的优点:
- 顶部集中导入依赖。
- 中间定义可复用函数。
- 将主流程放入
main()。 - 用
if __name__ == '__main__'控制是否执行主流程。
这有助于测试、导入复用和命令行执行。
命令行工具
Python 常用于编写命令行工具,例如:
python3 report.py portfolio.csv prices.csv
命令行工具通常从 shell/terminal 中执行,用于:
- 自动化任务
- 后台作业
- 数据处理
- 文件转换
- 报告生成
- 管道处理
这部分与 命令行工具设计、Python自动化脚本 有关。
命令行参数:sys.argv
命令行本质上是一组文本字符串。运行:
python3 report.py portfolio.csv prices.csv
对应的参数列表可从 sys.argv 获取:
sys.argv # ['report.py', 'portfolio.csv', 'prices.csv']
常见处理方式:
import sys
if len(sys.argv) != 3:
raise SystemExit(f'Usage: {sys.argv[0]} portfile pricefile')
portfile = sys.argv[1]
pricefile = sys.argv[2]
要点:
sys.argv[0]是脚本名。- 后续元素是用户传入的参数。
- 参数数量错误时,可抛出
SystemExit并打印用法说明。
标准输入输出:stdio
Python 中标准输入输出对象位于 sys 模块:
sys.stdout
sys.stderr
sys.stdin
默认行为:
print()输出到sys.stdout。input()从sys.stdin读取。- traceback 和错误信息输出到
sys.stderr。
stdio 对象和普通文件类似,但它们可能连接到:
- 终端
- 文件
- 管道
- 其他进程
例如:
python3 prog.py > results.txt
cmd1 | python3 prog.py | cmd2
这说明 Python 脚本可以自然地参与 shell 重定向和管道工作流。相关概念可扩展为 标准输入输出与管道。
环境变量
环境变量由 shell 设置,例如:
setenv NAME dave
setenv RSH ssh
python3 prog.py
在 Python 中可通过 os.environ 访问:
import os
name = os.environ['NAME']
os.environ 是一个类似字典的对象,保存当前进程环境变量。程序对环境变量的修改会反映到之后由该程序启动的子进程中。
相关主题可归入 环境变量、Python进程环境。
程序退出
Python 程序退出可通过异常机制完成:
raise SystemExit
raise SystemExit(exitcode)
raise SystemExit('Informative message')
也可以使用:
import sys
sys.exit(exitcode)
要点:
SystemExit是用于终止程序的异常。- 非零退出码表示错误。
- 字符串参数可用于输出提示信息。
相关概念可扩展为 程序退出码与错误处理。
#! 行与可执行脚本
在 Unix 系统中,可以在脚本第一行加入 shebang:
#!/usr/bin/env python3
然后赋予可执行权限:
chmod +x prog.py
之后即可直接运行:
prog.py
说明:
#!行告诉系统用哪个解释器运行脚本。#!/usr/bin/env python3会在环境路径中查找python3。- Windows 的 Python Launcher 也会查看
#!行以判断 Python 版本。
相关主题可归入 shebang与脚本执行。
命令行脚本模板
最终推荐的命令行脚本模板如下:
#!/usr/bin/env python3
# prog.py
import modules
def spam():
...
def blah():
...
def main(argv):
# Parse command line args, environment, etc.
...
if __name__ == '__main__':
import sys
main(sys.argv)
该模板综合了本文的主要实践:
- 使用 shebang 支持直接执行。
- 将业务逻辑封装在函数中。
main(argv)接收参数列表,便于测试和交互调用。- 仅在作为主程序运行时导入
sys并调用main(sys.argv)。 - 保持模块导入时无副作用。
练习内容
Exercise 3.15:添加 main() 函数
要求修改 report.py:
- 添加一个接受命令行参数列表的
main()函数。 - 能够在交互式环境中调用:
import report
report.main(['report.py', 'Data/portfolio.csv', 'Data/prices.csv'])
并输出股票报告。
同时修改 pcost.py,使其也有类似的 main():
import pcost
pcost.main(['pcost.py', 'Data/portfolio.csv'])
输出总成本。
Exercise 3.16:制作可执行脚本
要求进一步修改 report.py 和 pcost.py,使它们能在命令行执行:
python3 report.py Data/portfolio.csv Data/prices.csv
python3 pcost.py Data/portfolio.csv
这要求脚本使用 if __name__ == '__main__' 调用 main(sys.argv),从而兼顾导入复用与命令行运行。
核心结论
本文的关键贡献是把 Python 程序从“直接写一串顶层语句”推进到更规范的脚本结构:
- Python 没有内建
main(),但有主模块概念。 if __name__ == '__main__'是区分直接运行与导入复用的标准方式。- 将主逻辑封装进
main(argv)可以提高可测试性和可维护性。 - 命令行脚本通常需要处理
sys.argv、stdio、环境变量和退出码。 - 使用 shebang 与可执行权限可以让 Python 文件像普通 Unix 命令一样运行。
这些实践共同构成了 Python 命令行程序的基本结构,与 Python程序入口、命令行工具设计、标准输入输出与管道 密切相关。