首页
/ 深入解析 CPython `sys` 模块:解释器状态、运行时控制与内置工具的完整参考

深入解析 CPython `sys` 模块:解释器状态、运行时控制与内置工具的完整参考

2026-09-08 00:00:12作者:苗圣禹Peter

sys 是 CPython 解释器内置的"系统参数与函数"模块,它为每一段 Python 代码提供访问解释器内部状态(版本、ABI、路径、flags、标准流)和与之深度交互的能力。本文以 CPython 官方库文档 Doc/library/sys.rst 为主线,逐类讲解其全部公开数据与函数,并对照 Python/sysmodule.c 中的实际实现(模块初始化入口 _PySys_InitCore 位于 Python/sysmodule.c#L4001-L4368)给出源码级佐证,帮助读者系统掌握这一模块并能正确、安全地在脚本、调试器、性能分析器与库代码中使用它。

sys 模块是什么:定位、可用性与基本读写约定

按文档开头定义,sys 模块提供了对解释器维护的若干变量以及与解释器深度交互的函数的访问,并且始终可用(built-in,编译进解释器核心,无需 import 前的任何引导过程)。其实现的底层正是 Python/sysmodule.c_PySys_InitCore 通过 SET_SYS(...) 宏把各项数据灌入模块字典的过程。

使用时有几条约定需要牢记:

  • 除非显式注明,所有变量都是只读的;能修改的变量(如 sys.pathsys.ps1sys.tracebacklimit)文档会逐条说明。
  • 带前导下划线的成员(如 sys._current_framessys._getframesys._jit)属于 CPython 内部专用 API:文档标注为 internal and specialized purposes only不保证存在于其他 Python 实现(PyPy、Jython 等)中,也不保证跨版本行为稳定,编写可移植代码时应避免依赖。
  • 文档对每个成员标注了引入版本(versionadded)与行为变更版本(versionchanged),本仓库对应文档已覆盖到 3.15 / 3.16 的新特性(例如 abi_info 于 3.15 引入、lazy imports 系列函数于 3.15 引入、sys._clear_type_cache 于 3.16 成为 no-op),编写代码时可根据这些标注判断特性可用性。

解释器身份:版本、ABI 与实现信息

sys.versionsys.version_info:不要解析字符串

  • sys.version 是一个包含版本号、构建号与所用编译器信息的字符串,交互式启动时显示的 banner 即取自它。
  • 官方明确警告:不要从该字符串中提取版本信息,应改用 sys.version_infoplatform 模块。

sys.version_info 是一个五元组命名元组:(major, minor, micro, releaselevel, serial),其中 releaselevel 取值 'alpha''beta''candidate''final'。Python 2.0 对应 (2, 0, 0, 'final', 0)。既支持下标 sys.version_info[0],也支持字段访问 sys.version_info.major。用它可以写出清晰的版本分支:

import sys

if sys.version_info >= (3, 12):
    pass  # 使用 3.12+ 的新特性
  • sys.hexversion:把版本号编码为单个整数的形式,保证随版本单调递增。它的典型用法是 if sys.hexversion >= 0x010502F0:("至少 1.5.2")。之所以叫 hexversion,是因为只有转成 hex() 输出才可读。更易读的等价物就是 version_info
  • sys.api_version:C API 版本,等价于 C 宏 PYTHON_API_VERSION,仅为向后兼容而保留;文档注明目前该常量在新版本中不再更新,不适合用于版本判断
  • sys.maxunicode:最大 Unicode 码点 11141110x10FFFF)。PEP 393 之前它可能是 0xFFFF0x10FFFF(取决于 UCS-2/UCS-4 编译选项),此后恒为完整码点空间。

sys.implementation:实现信息对象(PEP 421)

包含所有 Python 实现都必须提供的属性:

属性 含义
name 实现标识符,如 'cpython',保证小写
version version_info 同格式的命名元组,表示实现自身版本(与"语言标准版本"语义不同;CPython 是参考实现所以两者相同)
hexversion 十六进制格式的实现版本,类似 sys.hexversion
cache_tag 导入机制写 .pyc 缓存文件名所用的标签,如 'cpython-313';若为 None 表示禁用模块缓存
supports_isolated_interpreters 是否支持多个隔离解释器(PEP 684/PEP 734),CPython 在多数平台为 True,对应低层 _interpreters 模块

各实现可追加以单下划线开头的私有属性。该对象在一次运行内不会变化。属性由 Python/sysmodule.c 中的 _PySys_InitCore 写入 sys 字典。

sys.abi_info(3.15 新增)与 sys.abiflags

sys.abi_info(3.15 新增)是一个描述当前解释器 ABI 的对象。它不编码基础操作系统(Linux 或 Windows),但包含会在同一台机器上并存的不同构建变体间产生差异的信息(例如指针宽度,因为有的系统同时提供 32 位与 64 位构建)。其条目在所有平台上保持一致(如 64 位专有架构上也有 pointer_size)。可用属性:

  • abi_info.pointer_bits:指针位宽整数,等价 8 * sizeof(void *),通常为 3264
  • abi_info.free_threaded:是否以 free-threading(--disable-gil configure 选项,Windows 上是 DisableGil 属性)构建;
  • abi_info.debug:是否 debug 构建(--with-pydebug 或 Windows Debug 配置);
  • abi_info.byteorder:字节序字符串 'big' / 'little',与 sys.byteorder 相同。

其构建逻辑可见 Python/sysmodule.cmake_abi_info()(创建 dict 后 _PyNamespace_New 包成命名空间对象)。

sys.abiflags:在 POSIX 上使用标准 configure 脚本构建时,按 PEP 3149 提供 ABI 标志字符串。3.8 起默认标志为空字符串(原先表示 pymalloc 的 m 标志已被移除)。仅 Unix 可用。

sys.byteordersys.maxsize

  • sys.byteorder'big'(大端)或 'little'(小端)。
  • sys.maxsizePy_ssize_t 可容纳的最大值,32 位平台通常为 2**31-1,64 位平台通常为 2**63-1。常用于生成大列表等容量判断。

平台与构建信息:platform、platlibdir、线程与浮点细节

sys.platform:平台标识字符串

sys.platform 返回平台标识。常用取值包括:AIX → 'aix'、Android → 'android'、Emscripten → 'emscripten'、FreeBSD → 'freebsd'、iOS → 'ios'、Linux → 'linux'、macOS → 'darwin'、Windows → 'win32'、Windows/Cygwin → 'cygwin'、WASI → 'wasi'。未列出的 Unix 系统返回构建时 uname -s 小写加 uname -r 主版本,例如 'sunos5'。为兼容带版本号的历史行为(linux2/aix5/freebsd13 等),官方推荐用前缀判断而非全等比较:

if sys.platform.startswith('sunos'):
    # SunOS-specific code here...

需要注意它的粒度:os.name 粒度更粗,platform 模块提供更精细的系统身份检查。

sys.platlibdir(3.9 新增)与 sys.dllhandle

sys.platlibdir 是平台相关库目录名,用于拼出标准库与扩展模块的安装路径。多数平台为 "lib";Fedora/SuSE 的 64 位平台为 "lib64",此时:

  • /usr/lib64/pythonX.Y/:标准库(如 os.py);
  • /usr/lib64/pythonX.Y/lib-dynload/:标准库 C 扩展(如 errno);
  • /usr/lib/pythonX.Y/site-packages/(总是 lib,不用 platlibdir):第三方纯 Python 包;
  • /usr/lib64/pythonX.Y/site-packages/:第三方 C 扩展。

sys.dllhandle:Python DLL 的句柄(整数),Windows 专用。sys.winver:Windows 上用于构成注册表键的版本号(DLL 中字符串资源 1000),仅为信息用途,修改它不影响注册表。

sys.thread_info:线程实现详情

命名元组,给出线程实现信息:

  • name"nt"(Windows)、"pthread"(POSIX)、"pthread-stubs"(无线程的 WebAssembly 平台桩实现)、"solaris"
  • lock:锁实现 —— "semaphore"(3.14 及更早)、"mutex+cond"(3.14 及更早)、"pymutex"(3.15 起使用 PyMutex)、未知则为 None
  • version:线程库名称与版本,未知为 None

sys.float_infosys.float_repr_stylesys.hash_info

sys.float_info 命名元组对应 C 标准头文件 float.h 中的宏,反映当前平台 double 的精度与内部表示。完整的 12 个属性与 float.h 宏对应如下:

sys.float_info 属性 float.h 宏 含义
epsilon DBL_EPSILON 1.0 与大于 1.0 的最小可表示 float 之差(可用 math.ulp 对照)
dig DBL_DIG 可被 float 忠实表示的十进制最大位数(往返转换不改变值)
mant_dig DBL_MANT_DIG 尾数中 radix 进制位数(float 精度)
max DBL_MAX 最大有限正 float
max_exp DBL_MAX_EXP 使 radix**(e-1) 可表示的最大整数 e
max_10_exp DBL_MAX_10_EXP 使 10**e 在可表示范围内的最大整数 e
min DBL_MIN 最小正规化正 float;最小的正非正规化数用 math.ulp(0.0) 获取
min_exp DBL_MIN_EXP 使 radix**(e-1) 为正规化的最小整数 e
min_10_exp DBL_MIN_10_EXP 使 10**e 为正规化的最小整数 e
radix FLT_RADIX 指数表示基数
rounds FLT_ROUNDS 舍入模式:-1 不可判定、0 向零、1 就近、2 向正无穷、3 向负无穷

dig 的含义值得展开:若十进制字符串 s 的有效位数不超过 dig,则 float(s) 再格式化回去值不变:

>>> import sys
>>> sys.float_info.dig
15
>>> s = '3.14159265358979'    # 15 位有效数字:往返安全
>>> format(float(s), '.15g')
'3.14159265358979'
>>> s = '9876543211234567'    # 16 位有效数字:往返会改变值!
>>> format(float(s), '.16g')
'9876543211234568'

sys.float_repr_style'short' 表示 repr(x) 追求最短且满足 float(repr(x)) == x(3.1 起的标准行为);否则为 'legacy'(3.1 之前旧行为)。

sys.hash_info:数值哈希实现参数,包括 width(哈希位宽)、modulus(数值哈希方案的素数模 P)、inf(正无穷哈希值)、imag(复数虚部乘子)、algorithm(str/bytes/memoryview 的哈希算法名)、hash_bits/seed_bits(算法内部输出与种子位数)、cutoff(小字符串 DJBX33A 优化的区间上界 [1, cutoff))。其中 nan 属性已不再使用。

sys.int_info:大整数内部表示

命名元组(只读属性):

  • int_info.bits_per_digit:每"位组(digit)"的位数,Python 整数内部按 2**bits_per_digit 进制存储;
  • int_info.sizeof_digit:表示 digit 的 C 类型字节数;
  • int_info.default_max_str_digits:未显式配置时 sys.get_int_max_str_digits() 的默认值;
  • int_info.str_digits_check_thresholdsys.set_int_max_str_digitsPYTHONINTMAXSTRDIGITS-X int_max_str_digits 允许的非零最小值。

其他平台专属函数

  • sys.getwindowsversion()(Windows):返回含 majorminorbuildplatformservice_packservice_pack_minorservice_pack_majorsuite_maskproduct_typeplatform_version 的命名元组;product_type1 为工作站(VER_NT_WORKSTATION)、2 为域控制器、3 为非域控服务器;platform_version 反映真实 OS 版本(用于日志,不宜做特性探测),建议精确 OS 版本用 platform 模块。封装自 Win32 GetVersionEx
  • sys.getandroidapilevel()(Android):返回构建期 Android API level(本构建可运行的最低版本),运行时版本用 platform.android_ver()
  • sys._emscripten_info(Emscripten,3.11 起):命名元组,含 emscripten_versionruntime(浏览器 UA 或 'Node.js v...''UNKNOWN')、pthreadsshared_memory

命令行参数与解释器 flags

sys.argvsys.orig_argv

sys.argv 是传给 Python 脚本的命令行参数列表:

  • argv[0] 是脚本名(是否为完整路径取决于操作系统);
  • -c 执行代码时 argv[0]'-c'
  • 未传脚本名(直接进 REPL)时 argv[0] 为空字符串。

处理命令行传入文件可考虑标准库 fileinputUnix 注意:命令行参数从 OS 以字节传入,Python 用文件系统编码加 surrogateescape 解码;需要原始字节时可 [os.fsencode(arg) for arg in sys.argv]

sys.orig_argv(3.10 起):传给 Python 可执行文件本身的原始参数。与 argv 的差别是:解释器自己消费掉的参数(如 -X-E 等)会出现在 orig_argv 中而不会出现在 argv 里。

sys.flags:命令行 flags 快照

只读命名元组,暴露各命令行开关的生效状态,文档建议只按名称访问。属性与来源选项对应表:

sys.flags 属性 来源命令行选项 / 环境变量
debug -d
inspect / interactive -i
isolated -I
optimize -O / -OO
dont_write_bytecode -B
no_user_site -s
no_site -S
ignore_environment -E
verbose -v
bytes_warning -b
quiet -q
hash_randomization -R
dev_mode -X dev(Python 开发模式,见 Doc/library/devmode.rst
utf8_mode -X utf8
safe_path -P
int_max_str_digits -X int_max_str_digits
warn_default_encoding -X warn_default_encoding
gil -X gilPYTHON_GIL(3.13 加入)
thread_inherit_context -X thread_inherit_contextPYTHON_THREAD_INHERIT_CONTEXT(3.14 加入)
context_aware_warnings -X context_aware_warningsPYTHON_CONTEXT_AWARE_WARNINGS(3.14 加入)

从源码结构看,这些字段在 Python/sysmodule.c_PySys_InitCore 初始化阶段一次性写入,因此脚本运行时读取到的是启动时快照。

sys._xoptions-X 选项字典

CPython 特有:以字典形式暴露 -X 传入的各类实现级选项。有显式值的选项映射为值、无值选项映射为 True

$ ./python -Xa=b -Xc
>>> import sys
>>> sys._xoptions
{'a': 'b', 'c': True}

路径系统、安装前缀与导入机制

模块搜索路径:sys.path

sys.path 是模块搜索路径字符串列表,由 PYTHONPATH 加安装相关默认值初始化。启动时会(在 PYTHONPATH 插入项之前)预置一个"潜在不安全"路径:

  • python -m module:前置当前工作目录;
  • python script.py:前置脚本所在目录(符号链接会被解析);
  • python -c code 与直接 python:前置空字符串,等价当前工作目录。

-PPYTHONSAFEPATH 可禁止该预置。程序可以自由增删 sys.path 实现自定义导入,但只能加入字符串,其他类型在导入时被忽略。扩展 sys.path.pth 文件机制见标准库 site 模块。

导入系统的三方变量:sys.meta_pathsys.path_hookssys.path_importer_cachesys.modules

  • sys.meta_path元路径查找器列表,导入模块时逐个调用其 find_spec(name, path=None)(PEP 451 起;3.12 起移除了回退 find_module 的兼容逻辑)。默认条目实现了 Python 标准导入语义。包内模块会传入父包 __path__
  • sys.path_hooks:可调用对象列表,接收路径参数、尝试创建 finder;成功返回 finder,失败抛 ImportError。机制源于 PEP 302。
  • sys.path_importer_cache:finder 缓存字典,键为交给 path_hooks 的路径;路径有效但找不到 finder 时存 None
  • sys.modules:已加载模块名 → 模块对象的字典。可操作它强制重载模块等;但替换整个字典不一定按预期工作,删除关键项可能使 Python 崩溃。遍历全局字典务必用 sys.modules.copy()tuple(sys.modules),避免并发迭代时大小变化抛异常。

内置模块与标准库模块清单

  • sys.builtin_module_names:编译进当前解释器的全部模块名字符串元组(这些信息无法从 modules.keys() 获得,因为后者只含已导入模块)。含纯 Python、built-in、frozen 与 extension 四种类型。
  • sys.stdlib_module_names(3.10 起):标准库模块名 frozenset,各平台一致(平台上不可用或被禁用的模块也在其中),仅列包主名(email 在列,而 email.mimeemail.message 不在)。

安装前缀与虚拟环境:prefixexec_prefixbase_prefixbase_exec_prefix

  • prefix:平台无关文件安装目录(Unix 默认 /usr/local,可用 configure --prefix 修改)。exec_prefix:平台相关文件(如共享库、配置文件)前缀,默认同 /usr/local,可用 --exec-prefix 指定;{exec_prefix}/lib/pythonX.Y/config 放配置(如 pyconfig.h),{exec_prefix}/lib/pythonX.Y/lib-dynload 放共享库扩展。
  • 在虚拟环境中:prefix/exec_prefix 被改写为 venv 前缀,而 base_prefix/base_exec_prefix 不变、始终指向基础安装(3.3 起)。
  • 3.14 行为变更:处于 venv 时 prefix/exec_prefix路径初始化(而非 site 模块)设为 venv 前缀,因此即使 -S 禁用 site,这两个值也总指向 venv。相关机制详见 Doc/library/sys_path_init.rst

sys.executable 与文件系统编码

  • sys.executable:解释器可执行文件的绝对路径;无法获取真实路径时为空字符串或 None
  • sys.getfilesystemencoding() / sys.getfilesystemencodeerrors():返回文件系统编码及其错误处理器(用于 Unicode 文件名与字节文件名互转)。3.6 起 Windows 不再保证返回 'mbcs'(见 PEP 529);3.7 起开启 Python UTF-8 Mode 时返回 'utf-8'。二者在启动时由 PyConfig_Read 依据 PyConfig.filesystem_encoding / filesystem_errors 配置。日常转换请用 os.fsencode/os.fsdecode
  • sys.getdefaultencoding():返回 'utf-8',即默认字符串编码名。

标准流:stdin / stdout / stderr 及其原始版本

sys.stdinsys.stdoutsys.stderr 是解释器用于标准输入/输出/错误的文本文件对象

  • stdin:一切交互式输入(含 input());
  • stdoutprint 与交互表达式输出、input() 的提示符;
  • stderr:解释器自身提示与错误消息。

参数选择规则:

  • 编码与错误处理初始化自 PyConfig.stdio_encoding / stdio_errors。Windows 上控制台设备用 UTF-8;磁盘文件/管道用系统 ANSI 代码页;字符设备(isatty() 为真)分别使用启动时控制台输入/输出代码页。设 PYTHONLEGACYWINDOWSSTDIO 可关闭控制台特殊行为。所有平台可用 PYTHONIOENCODING 环境变量或 -X utf8 / PYTHONUTF8 覆盖(Windows 控制台例外,需同时设 PYTHONLEGACYWINDOWSSTDIO)。
  • 缓冲:交互时 stdout 行缓冲,否则与普通文本文件一样块缓冲;stderr 两种情况下都行缓冲(3.9 起非交互 stderr 也从全缓冲改为行缓冲)。用 -uPYTHONUNBUFFERED 可让两者无缓冲。
  • 写二进制数据用底层 sys.stdout.buffer.write(b'abc')。但库代码需注意标准流可能被替换成 io.StringIO 这类无 buffer 属性的对象。

sys.__stdin__sys.__stdout__sys.__stderr__ 保存程序启动时 stdin/stdout/stderr 的原始值,用于终结阶段,或在标准流被替换后仍向真实流输出、或在流对象损坏时恢复。需要注意:Windows GUI 程序(未连接控制台)与 pythonw 启动的程序中,这些对象可能为 None

交互式会话的钩子与提示符

sys.displayhooksys.__displayhook__

交互会话中,对表达式求值结果会调用 sys.displayhook(参数为结果值)。默认行为是:值非 None 时把 repr(value) 打印到 sys.stdout 并存入 builtins._;若 repr 结果无法用 stdout.encoding/errors 编码,则用 backslashreplace 错误处理器编码(3.2 起)。文档给出的伪代码展示了 _None 防递归、捕获 UnicodeEncodeError 后写 buffer 等细节。可通过赋值单参函数定制 REPL 结果展示。原始实现保存在 sys.__displayhook__

sys.breakpointhooksys.__breakpointhook__

内建 breakpoint() 调用的钩子,默认进入 pdb 调试器。其行为链:

  1. 先查看环境变量 PYTHONBREAKPOINT
  2. 若为 "0",立即返回(no-op);
  3. 未设置或为空字符串 → 调用 pdb.set_trace()
  4. 否则按点号导入语法 package.subpackage.module.function 导入并调用,breakpoint()*args/**kws 原样透传,返回值原样返回给 breakpoint()

导入失败时报 RuntimeWarning 并忽略断点。若以编程方式覆盖了 sys.breakpointhook()PYTHONBREAKPOINT 将不再被查阅。自定义调试器时,把它绑到期望额外参数的回调即可让 breakpoint() 直接调用。

sys.ps1 / sys.ps2sys.__interactivehook__

  • ps1/ps2:交互模式主/次提示符字符串(初始 '>>> ''... '),仅交互模式下定义。若赋值为非字符串对象,每次读取命令前会重新对其求 str(),可实现动态提示符。
  • __interactivehook__(3.4 起):存在时,解释器进入交互模式后自动无参调用(在 PYTHONSTARTUP 文件读取之后执行,因此可在其中设置)。site 模块会设置它以启用 rlcompleter。调用时触发审计事件 cpython.run_interactivehook

顶层异常处理:excepthook、unraisablehook 与 last_exc

sys.excepthook(type, value, traceback)

当非 SystemExit 异常未被捕获时,解释器调用 sys.excepthook 把回溯与异常打印到 sys.stderr:交互会话中在回到提示符之前,脚本中在进程退出之前。可通过赋值一个三参函数自定义顶层未捕获异常的处理(日志落盘、上报等)。触发时会产生审计事件 sys.excepthook(参数 hook, type, value, traceback;hook 未设时为 None)。另外 threading.excepthook 处理 Thread.run() 抛出的异常。

sys.unraisablehook(unraisable, /)

处理"无法上报"的异常(如析构器抛异常、gc.collect() 期间出错)。unraisable 对象含属性:exc_typeexc_value(可 None)、exc_traceback(可 None)、err_msg(可 None)、object(引起异常的对象,可 None)。默认钩子按 f'{err_msg}: {object!r}' 格式化,err_msgNone 时用 "Exception ignored in" 消息;3.15 起默认带彩色文本,可用颜色相关环境变量关闭。覆盖它可控制"Exception ignored in"类消息的处理。警告:自定义钩子保存 exc_value 可能制造引用环,应显式清理;保存 object 可能"复活"正在终结的对象,钩子返回前应避免留存。触发审计事件 sys.unraisablehook

sys.__excepthook__sys.__unraisablehook__ 保存程序启动时上述两钩子的原始值,供恢复。

sys.exception()sys.exc_info()

  • sys.exception()(3.11 起):在异常处理器(except/except*)执行期间返回当前捕获的异常实例(嵌套时仅最内层可见),否则返回 None
  • sys.exc_info():旧式表示 —— 正在处理异常 e 时返回 (type(e), e, e.__traceback__);无异常时返回三个 None。3.11 起 type 与 traceback 字段从 value 推导,因此异常在处理器中被修改时后续调用会反映改动。

sys.last_exc 与废弃的 last_type/last_value/last_traceback

sys.last_exc(3.12 起)在未捕获异常导致解释器打印错误与回溯后被设置,供交互用户直接 import pdb; pdb.pm() 做事后(post-mortem)调试,无需重跑出错的命令。last_type/last_value/last_traceback 三变量已废弃,仅保存 last_exc 的旧式表示。

sys.tracebacklimit

设为整数时决定未处理异常打印的回溯层数上限。默认 1000;设为 0 或负数时完全抑制回溯,仅打印异常类型与值。

sys.exception()sys.excepthooksys.exit 的关系

sys.exit([arg]) 实际是抛 SystemExitarg 为整数则作为退出码(0 为成功,非零为异常终止;多数系统要求 0–127);None 等价 0;其他对象打印到 stderr 并以退出码 1 结束,sys.exit("some error message") 即快速报错退出。由于它"只是抛异常",只有主线程且异常未被拦截时才真正结束进程;finally 清理照常执行,外层也可拦截退出尝试。3.6 起若捕获 SystemExit 后的清理(如刷新缓冲)出错,退出码改为 120。

审计机制:sys.auditsys.addaudithook(PEP 578)

sys.audit(event, *args)

触发审计事件并调用所有活动审计钩子。event 是标识事件的字符串,args 携带可选附加信息;某事件的参数数量与类型属于公共稳定 API,发布间不应修改。示例:事件 os.chdir 携带参数 path(请求切换的目标目录)。sys.audit 会依次调用已有钩子并重新抛出第一个钩子抛出的异常;一般原则是异常不应被吞掉,应尽快终止进程——钩子据此决定仅记录还是中止操作。其原生等价函数为 C API PySys_Audit(优先使用原生版本)。全部事件表见 Doc/library/audit_events.rst

sys.addaudithook(hook)

把可调用对象追加到当前(子)解释器的活动审计钩子列表。sys.audit 触发事件时按添加顺序调用每个钩子,传入事件名与参数元组。钩子可记录、抛异常中止操作或直接终止进程。行为要点:

  • C API PySys_AddAuditHook 添加的原生钩子先于 Python 层钩子被调用;
  • sys.addaudithook 自身也会触发审计事件 sys.addaudithook(无参数);若已有钩子抛出 RuntimeError 派生异常,新钩子不添加且该异常被抑制(3.8.1 起 RuntimeError 之外的 Exception 不再被抑制),因此调用方不能假定钩子一定已注册;
  • 官方明确警告:审计钩子适合收集内部或不可观测动作的信息,不适合实现"沙箱"——恶意代码可轻易禁用或绕过 Python 层钩子。安全敏感钩子至少应在运行时初始化前通过 C API PySys_AddAuditHook 注册,并彻底移除或严密监控 ctypes 这类允许任意内存修改的模块;
  • 实现细节:开启跟踪(settrace)时,Python 钩子仅在其 __cantrace__ 成员为真值时才被跟踪。

sys 模块自身涉及的大量审计事件(如 sys._current_framessys.excepthooksys.settracesys.unraisablehooksys.remote_exec 等)都在各条目下标注,可在 Doc/library/audit_events.rst 中集中查阅。

运行调控:递归限制、线程切换与整数转换限制

递归限制

  • sys.getrecursionlimit() / sys.setrecursionlimit(limit):读取/设置 Python 解释器栈最大深度,防止无限递归撑爆 C 栈导致崩溃。最高可行限制平台相关;调高需谨慎,过高会崩溃。若新限制低于当前递归深度,立即抛 RecursionError(3.5.1 起)。

线程切换间隔

  • sys.getswitchinterval() / sys.setswitchinterval(interval):读写解释器线程切换间隔(秒)。它决定并发 Python 线程"时间片"的理想时长;实际值可能更高(尤其执行长内部函数时),且间隔结束后调度哪个线程由操作系统决定——解释器没有自己的调度器。3.2 起可用。

整数↔字符串转换长度限制

  • sys.get_int_max_str_digits() / sys.set_int_max_str_digits(maxdigits)(3.11 起):读写整数十进制字符串转换长度限制(拒绝超长整数与字符串互转,抵御基于 int() 的拒绝服务)。相关常量见 sys.int_info.default_max_str_digitsstr_digits_check_threshold。实现于 Python/sysmodule.csys_get_int_max_str_digits_impl / sys_set_int_max_str_digits_impl(约 L1881-L1900)。

内存与性能内省工具

  • sys.getallocatedblocks():当前解释器分配的内存块总数(与大小无关),主要用来跟踪内存泄漏;受内部缓存影响结果会波动,可先 _clear_internal_caches()gc.collect() 让结果更稳定。无法计算的构建允许返回 0。
  • sys.getunicodeinternedsize()(3.12 起):已驻留(interned)的 unicode 对象数量。
  • sys.getsizeof(object[, default]):对象占用内存字节数。只统计直接归因于该对象的内存,不含其引用的对象;调用 __sizeof__ 并叠加 GC 开销(若对象由 GC 管理)。对象不提供大小探测时返回 default,否则抛 TypeError
  • sys.getrefcount(object):返回对象的引用计数,通常比预期高 1(因为包含作为实参传入的临时引用)。注意返回值不一定反映真实持有引用数——3.12 起**不灭对象(immortal)**引用计数极大。除 0 或 1 外不要依赖精确值;可用 sys._is_immortal 判断对象是否不灭。
  • sys._clear_type_cache()(3.13 起废弃,3.16 起为 no-op)与 sys._clear_internal_caches()(3.13 起):清除内部性能缓存。文档提醒 在排查泄漏、需要释放多余引用与内存块时使用;3.16 起类型缓存已改为按类型实现、不再清除。
  • sys._debugmallocstats():向 stderr 打印 CPython 内存分配器底层状态;debug 构建(--with-pydebug)下还会做昂贵的内部一致性检查。输出格式未定义、可能变化(CPython 实现细节)。
  • sys._is_immortal(op)(3.14 起)与 sys._is_interned(string)(3.13 起):分别判断对象是否不灭、字符串是否驻留,专供内部与特化用途。
  • sys.intern(string):把字符串加入驻留表并返回驻留后的字符串(可能复制)。驻留后字典键可先哈希后指针比较而非字符串比较,提高查找性能。程序中模块/类/实例属性字典的键通常自动驻留。驻留字符串并非不灭,需持有返回值引用方能获益。

跟踪、调试与分析:settrace / setprofile 及其事件模型

sys.settrace(tracefunc) 与局部跟踪

设置系统跟踪函数,使你能用 Python 实现调试器。跟踪函数线程相关——调试多线程需为每个线程注册(或用 threading.settrace)。跟踪函数签名 (frame, event, arg)

  • 'call':进入新的局部作用域;全局跟踪函数被调用,argNone返回值指定该作用域的局部跟踪函数(返回 None 则不跟踪)。
  • 'line':即将执行新代码行或重执行循环条件;局部跟踪函数被调用,argNone;返回值指定新的局部跟踪函数。可设置 frame.f_trace_lines = False 关闭该帧的逐行事件。执行细节见 InternalDocs/code_objects.md
  • 'return':函数即将返回;arg 为返回值,异常引发返回时为 None;返回值被忽略。
  • 'exception':发生异常;arg 为三元组 (exception, value, traceback);返回值为新局部跟踪函数。异常沿调用链向下传播时每一层都会产生 'exception' 事件
  • 'opcode'(3.7 起):即将执行新字节码;argNone;默认不发出,需显式置 frame.f_trace_opcodes = True 请求。

更精细用法:直接给 frame.f_trace = tracefunc 赋值(这也用于激活当前帧的跟踪,而 settrace 不会激活当前帧),但需先以 settrace 安装一个全局跟踪函数打开运行时跟踪机制——不要求是同一个函数,可用一个低开销、立即返回 None 禁用自身的函数。

跟踪函数出错会被自动解除(等同 settrace(None))。sys.gettrace() 返回当前跟踪函数。官方限定settrace/gettrace 仅面向调试器、性能分析器、覆盖率工具等,属于实现平台行为而非语言定义,其他 Python 实现未必提供。

sys.setprofile(profilefunc) 与配置事件

设置系统 profile 函数实现源码级性能分析器。与 trace 函数共用机制,但事件不同且不在每行代码上触发(仅 call/return;return 事件即使已设置异常也会上报)。profile 函数线程相关;文档提示有多个线程时上下文切换不可知,用它做性能分析意义有限。错误会导致自动解除。事件:

  • 'call':函数(或代码块)被调用;argNone
  • 'return':函数即将返回;arg 为返回值,异常引发返回时为 None
  • 'c_call':将调用 C 函数(扩展或内建);arg 为 C 函数对象;
  • 'c_return':C 函数返回;arg 为 C 函数对象;
  • 'c_exception':C 函数抛异常;arg 为 C 函数对象。

sys.getprofile() 读取当前 profile 函数。trace 函数内要递归地 trace(如调试器断点里),用 sys.call_tracing(func, args) —— 它保存/恢复跟踪状态并允许显式递归跟踪函数。

栈帧与线程内省

  • sys._getframe([depth]):返回调用栈第 depth 层帧对象(默认 0 = 栈顶);超过栈深抛 ValueError。触发审计事件 sys._getframe
  • sys._getframemodulename([depth])(3.12 起):返回调用栈第 depth 层所在模块名,无法识别返回 None。触发审计事件 sys._getframemodulename
  • sys._current_frames():返回线程 id → 该线程当前最顶层栈帧的字典。调试死锁最有用——无需死锁线程配合,其调用栈在死锁期间是冻结的。非死锁线程的帧在读取时可能已与实时活动无关。触发审计事件 sys._current_frames
  • sys._current_exceptions():线程 id → 该线程当前最顶层异常的字典;未在处理异常的线程不出现。3.12 起每个值为单一异常实例(而非 exc_info() 的三元组)。适合统计型性能分析。触发审计事件 sys._current_exceptions

协程与异步生成器调试

  • sys.set_coroutine_origin_tracking_depth(depth) / sys.get_coroutine_origin_tracking_depth()(3.7 起,provisional):启用后协程对象的 cr_origin 含 (文件名, 行号, 函数名) 元组序列,描述协程创建位置的栈回溯(最近的调用在前);depth 决定捕获的帧数,0 关闭。线程相关,仅供调试。
  • sys.set_asyncgen_hooks(firstiter=..., finalizer=...) / sys.get_asyncgen_hooks()(3.6 起,provisional,见 PEP 525):设置异步生成器首次迭代与将被 GC 时的回调,用于让事件循环调度其终结。底层是两个 C 调用,故触发两个审计事件 sys.set_asyncgen_hooks_firstitersys.set_asyncgen_hooks_finalizer。参考 finalizer 实现见 asyncio.Loop.shutdown_asyncgensLib/asyncio/base_events.py)。

GIL、Free-threading 与运行期状态查询

  • sys._is_gil_enabled()(3.13 起):GIL 启用返回 True。CPython 实现细节,不保证其他实现存在。
  • sys.is_finalizing():主解释器是否处于**关闭(shutdown)**过程;配合 PythonFinalizationError 使用。
  • sys._jit(3.14 起):观察即时编译的实验性子模块,不保证所有实现/版本/构建配置存在或行为一致
    • _jit.is_available():当前可执行文件是否支持 JIT(Windows 用 --experimental-jit 构建,其他平台 --enable-experimental-jit);
    • _jit.is_enabled():当前进程是否启用 JIT(可用环境变量 PYTHON_JIT=0/1 控制启动开关);启用隐含可用;
    • _jit.is_active():最顶层 Python 帧是否正在执行 JIT 代码。仅供测试调试 JIT 本身。文档示例提醒:由于跟踪型 JIT 的特性,基于其返回值做分支会产生"热行被编译成 JIT、断言行又回到解释器"的意外结果,反复调用可能返回不同值。
  • sys.monitoring:事件监控命名空间(注册回调、控制监控事件),详见 Doc/library/sys.monitoring.rst

Lazy Imports(3.15 新特性,PEP 810)

仓库对应的 3.15 文档为 sys 新增了一组 lazy imports(惰性导入)API,用于把 import 延迟到首次访问时执行:

  • sys.get_lazy_imports():返回当前模式字符串:"normal"(仅显式带 lazy 关键字的导入惰性化)或 "all"(所有顶层导入都"潜在惰性")。
  • sys.set_lazy_imports(mode):设置全局模式,仅接受上述两个字符串。文档明确此函数面向需要在整个应用层面控制惰性导入的高级用户;库开发者一般不应使用,因为它影响应用运行期执行。
  • sys.set_lazy_imports_filter(filter) / sys.get_lazy_imports_filter():设置/读取过滤器回调(None 清除)。过滤器对每次"潜在惰性"导入被调用以决定是否真的惰性化,签名为:
def filter(importing_module: str, imported_module: str,
           fromlist: tuple[str, ...] | None) -> bool:
    ...

三个位置参数分别为:执行导入的模块名、被导入模块的解析后全名(如 lazy from .spam import eggs 会传 package.spam)、from ... import 的名称元组(普通 import 为 None)。返回 True 允许惰性化,False 强制立即导入。

  • sys.lazy_modules(3.15 起):当前解释器中已惰性导入但尚未真正加载的完整模块名字符串集合;首次访问某惰性模块时其名被移出。该属性面向调试与内省。

平台/运行时扩展:远程调试与栈 trampoline

sys.remote_exec(pid, script)(3.14 起,PEP 768)

在 pid 对应的远程进程中执行 script 文件(内含 Python 代码)。函数立即返回;代码在目标进程主线程"下一个合适时机"执行(类似信号处理方式),没有任何接口获知执行完成——调用方必须保证脚本文件在远程进程读取时仍存在且未被覆盖。版本约束:两端必须是同 major/minor 的 CPython;任一端为预发布版(alpha/beta/rc)则必须完全同版本。触发两个审计事件:sys.remote_exec(在调用方进程,参数 pid 与脚本路径)与 cpython.remote_debugger_script(在远程进程)。详见 PEP 768 描述的远程调试机制。相关实现与 _remote_debugging 模块位于仓库 Modules/_remote_debugging

栈 profiler trampoline(Linux)

  • sys.activate_stack_trampoline(backend, /)(3.12 起,Linux):激活栈 profiler trampoline 后端,目前唯一支持 "perf"JIT 激活时无法激活 trampoline。常与 Linux perf 配合做解释器栈采样。
  • sys.deactivate_stack_trampoline():关闭当前 trampoline 后端;未激活时无效果。
  • sys.is_stack_trampoline_active():查询是否已激活。

sys._current_frames 审计下的动态库 flags(Unix)

  • sys.getdlopenflags() / sys.setdlopenflags(n)(Unix):读写解释器用于 dlopen 的 flags。sys.setdlopenflags(0) 导入模块时惰性解析符号;sys.setdlopenflags(os.RTLD_GLOBAL) 让符号跨扩展模块共享。符号名来自 os 模块的 RTLD_* 常量。

其他常用与杂项成员

  • sys.copyright:Python 解释器版权字符串。
  • sys.dont_write_bytecode:为真时不写 .pyc。初始值由 -BPYTHONDONTWRITEBYTECODE 决定,可自行赋值控制字节码生成。
  • sys.pycache_prefix(3.8 起):非 None 时,.pyc 写入/读取自以该目录为根的并行目录树(源码树里的 __pycache__ 被忽略)。相对路径按当前工作目录解析。初始值来自 -X pycache_prefix=PATHPYTHONPYCACHEPREFIX(命令行优先),都没设则为 None。若以 compileall 作预编译步骤,必须与运行期使用同一前缀。
  • sys.getobjects(limit[, type]):仅当以 --with-trace-refs 构建时存在,专用于调试 GC 问题;返回最多 limit 个动态分配对象(type 给定则仅该精确类型)。对象不安全、仅供特化场景;3.14 起结果可能包含共享同一对象分配器状态的其他解释器的对象(混用会崩溃)。
  • sys.warnoptions:warnings 框架的实现细节,不要修改

常用模式小结

在实际开发中,sys 的这些惯用法值得记忆:

  1. 版本分支:优先 sys.version_info/sys.hexversion,不要解析 sys.version 字符串。
  2. 平台分支sys.platform.startswith(...) 前缀匹配(兼容历史上带版本号的值),精细探测用 platform 模块。
  3. 路径相关:脚本目录用 os.path.dirname(__file__) 而非依赖 sys.path[0];自定义导入钩子写 sys.meta_path,插件路径注入改 sys.path
  4. 流重定向恢复:保存 sys.__stdout__/__stderr__ 原始对象,捕获异常后用 sys.excepthooktraceback.print_exc(file=sys.stderr) 输出。
  5. 调试死锁sys._current_frames() 是标准且无需协作的方案。
  6. 进程退出sys.exit()SystemExit,可在 finally/外层 except SystemExit 中拦截并做清理。
  7. 安全日志:用 sys.audit/addaudithook 采集内部动作;涉及安全的关键钩子走 C API 且在运行时初始化前注册,勿把它当沙箱。
  8. 内存排查_clear_internal_caches() + gc.collect() 后再 getallocatedblocks(),让结果可复现。

小结与延伸阅读

sys 是理解 CPython 运行时最直接的窗口:从 abi_infoimplementationversion_info 描述"解释器是什么",从 flagsargvpath 描述"解释器如何启动与找模块",从 settrace/setprofile/audit 描述"如何在 Python 层观察和干预解释器执行"。本文的源码级佐证可继续沿 Python/sysmodule.c_PySys_InitCoremake_abi_info 等)深入;版本特性对应文档 Doc/library/sys_path_init.rstDoc/library/audit_events.rstDoc/library/devmode.rstDoc/library/sys.monitoring.rst 提供了与本模块交互的完整细节。需要强调的是:sys 中大量成员是"实现平台行为而非语言定义"(官方 impl-detail 标注),编写跨实现(如 PyPy)兼容代码时,应只依赖 PEP 规定的必需成员。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388