sys 模块
命令行程序经常需要确认运行环境、接收参数并把错误交给调用方。如何知道当前使用的解释器,如何区分正常输出和错误输出,又如何返回执行结果?sys 模块用于和当前 Python 解释器交互,可以集中解决这些问题。
它和上一章的 os 模块关注点不同:
| 模块 | 主要职责 |
|---|---|
os | 文件、目录和操作系统功能 |
sys | Python 解释器和当前运行环境 |
本章将使用 sys 编写一个简单的命令行程序。
解释器环境
排查“为什么程序运行结果不一样”时,首先要确认使用的解释器版本和位置。
sys.executable
sys.executable 是当前 Python 解释器的路径:
import sys
print(sys.executable)在编辑器、虚拟环境和命令行使用不同解释器时,这个值也会不同。它可以帮助我们确认程序实际由哪个 Python 运行。
sys.version_info
sys.version_info 保存当前 Python 的版本信息:
import sys
print(sys.version_info)
print(sys.version_info.major)
print(sys.version_info.minor)需要判断版本时,直接比较版本信息,不要解析版本字符串:
import sys
if sys.version_info < (3, 14):
print("当前程序需要 Python 3.14 或更高版本")本课程示例默认使用 Python 3.14。
sys.platform
sys.platform 表示当前运行平台:
import sys
print(sys.platform)常见结果如下:
| 系统 | 常见值 |
|---|---|
| Windows | win32 |
| Linux | linux |
| macOS | darwin |
即使运行的是 64 位 Windows,结果通常仍然是 win32。它是平台标识,不表示处理器位数。
命令行参数
sys.argv 是一个列表,保存启动程序时传入的命令行参数。
创建 show_args.py:
import sys
print(sys.argv)在命令行中运行:
python3 show_args.py 张三 85一次运行结果:
['show_args.py', '张三', '85']其中:
sys.argv[0]表示程序入口,其内容会受到启动方式影响。sys.argv[1]开始才是传给程序的参数。- 命令行参数全部是字符串,数字需要自行转换。
参数数量校验
直接读取不存在的下标会抛出 IndexError。使用参数前应该先检查列表长度:
import sys
if len(sys.argv) != 3:
print("用法:python3 show_args.py <姓名> <成绩>")
else:
name = sys.argv[1]
score_text = sys.argv[2]
print(name, score_text)参数数量正确之后,还要根据业务要求检查参数格式和取值范围。
程序退出状态
sys.exit() 会结束当前程序。传入的整数称为退出状态:
0通常表示程序成功结束。- 非
0通常表示程序遇到错误。
import sys
if len(sys.argv) != 2:
print("参数数量错误")
sys.exit(2)
print(f"收到参数:{sys.argv[1]}")sys.exit() 执行后,后面的代码不会继续运行。它实际上会抛出 SystemExit,由 Python 解释器把退出状态返回给操作系统。
更完整的程序通常让 main() 返回状态码,再统一退出:
import sys
def main():
if len(sys.argv) != 2:
return 2
print(f"收到参数:{sys.argv[1]}")
return 0
if __name__ == "__main__":
sys.exit(main())这样能够把业务流程与程序退出动作分开。
标准流
命令行程序通常使用三条标准流:
| 标准流 | 主要用途 |
|---|---|
sys.stdin | 接收输入 |
sys.stdout | 输出正常结果 |
sys.stderr | 输出警告和错误 |
input() 默认从标准输入读取,print() 默认把内容写到标准输出:
name = input("请输入姓名:")
print(f"你好,{name}")需要直接读取一行时,可以使用 sys.stdin.readline():
import sys
line = sys.stdin.readline().rstrip("\n")
print(f"读取内容:{line}")这里使用 rstrip("\n") 只移除末尾换行符,不会无条件删除正常字符。
错误输出
错误信息应该写入标准错误流:
import sys
print("错误:成绩必须是整数", file=sys.stderr)正常结果和错误信息使用不同标准流后,命令行工具和自动化脚本就能分别处理它们。
输出重定向
不要为了写入文件而直接替换 sys.stdout。可以把文件对象传给 print():
with open("result.txt", "w", encoding="utf-8") as file:
print("程序运行结果", file=file)这种写法只影响当前这一次输出,不会改变整个程序的标准输出。程序运行日志将在下一章使用 logging 模块处理。
模块运行状态
模块章节已经介绍过搜索路径和导入缓存。sys 提供了对应的运行时信息。
sys.path
sys.path 保存模块搜索路径:
import sys
for path in sys.path:
print(repr(path))路径内容会受到解释器安装位置、虚拟环境和启动方式影响,因此不应该把某台计算机上的固定输出写进程序。
列表中的空字符串表示按当前工作目录搜索。第一项并不永远是空字符串:直接运行脚本、执行模块或进入交互环境时,都可能得到不同结果。
一般项目不应通过 sys.path.append() 临时修补导入问题。优先使用清楚的包结构和正确的程序入口。
sys.modules
sys.modules 是一个字典,保存当前进程已经加载的模块:
import math
import sys
print("math" in sys.modules)
print(sys.modules["math"])导入模块时,Python 会先检查这份缓存。同一个进程中再次导入已加载模块时,通常会直接复用模块对象。
不要手动修改 sys.modules。基础阶段只需要用它观察模块是否已经加载。
运行环境编码
标准流和文件系统都可能涉及编码。可以查看当前运行环境的实际配置:
import sys
print(sys.stdin.encoding)
print(sys.stdout.encoding)
print(sys.stderr.encoding)
print(sys.getfilesystemencoding())这些结果会受到终端、操作系统和启动配置影响。读写文本文件时仍然应该主动指定 encoding="utf-8",不要只依赖环境默认值。
综合案例:命令行成绩检查
需求: 从命令行接收姓名和成绩,校验成绩范围,输出等级,并通过退出状态告知调用方执行结果。
功能分析: 使用 sys.argv 读取参数,使用 sys.stderr 输出输入错误,使用 sys.executable 生成用法提示,使用 sys.exit() 返回状态码。
下面的程序从命令行接收姓名和成绩,并根据检查结果返回不同退出状态:
import sys
def parse_score(score_text):
try:
score = int(score_text)
except ValueError:
print("错误:成绩必须是整数", file=sys.stderr)
return None
if not 0 <= score <= 100:
print("错误:成绩必须在 0~100 之间", file=sys.stderr)
return None
return score
def get_level(score):
if score >= 90:
return "优秀"
if score >= 80:
return "良好"
if score >= 60:
return "及格"
return "不及格"
def main():
if len(sys.argv) != 3:
print(
f"用法:{sys.executable} {sys.argv[0]} <姓名> <成绩>",
file=sys.stderr,
)
return 2
name = sys.argv[1]
score = parse_score(sys.argv[2])
if score is None:
return 2
print(f"{name}:{score} 分,等级为{get_level(score)}")
return 0
if __name__ == "__main__":
sys.exit(main())传入正确参数:
python3 main.py 张三 85运行结果:
张三:85 分,等级为良好没有传入参数、成绩不是整数或成绩超出范围时,程序会把错误写入 stderr,并返回状态码 2。
这个案例串联了本章的核心内容:
- 使用
sys.argv接收参数。 - 使用
sys.stderr输出错误。 - 使用
sys.executable显示当前解释器。 - 使用
sys.exit()返回退出状态。
小结
sys.executable和sys.version_info用于确认解释器环境。sys.argv保存命令行参数,其中的参数都是字符串。sys.exit()可以结束程序,并向操作系统返回退出状态。stdin、stdout和stderr分别负责标准输入、正常输出和错误输出。sys.path保存模块搜索路径,sys.modules保存已加载模块。- 运行环境编码可能不同,读写文本文件时应主动指定编码。
练习
- 输出当前解释器路径、Python 主版本号、次版本号和系统平台。
- 编写一个命令行加法程序,接收两个数字并输出计算结果。
- 参数数量或数字格式错误时,把提示写入
stderr并返回非零状态。 - 导入一个标准库模块,再通过
sys.modules确认它已经加载。 - 输出当前标准输出编码和文件系统编码,比较两者是否相同。