CPython errno 模块完全指南:标准系统错误符号、errorcode 字典与 OSError 异常映射
发布时间:2026/9/8 23:23:05 锦皓数字建站

CPython errno 模块完全指南标准系统错误符号、errorcode 字典与 OSError 异常映射【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython本篇技术指南以 CPython 标准库文档 Doc/library/errno.rst 为主体系统讲解errno模块如何对外暴露底层操作系统Linux、macOS、Windows、WASI 等的 errno 系统错误符号。读完本文你将掌握errno 符号与整数值的对应关系、errno.errorcode反向字典的使用方法、如何通过os.strerror把数值错误码翻译为可读错误消息以及每个 errno 符号在 CPython 中如何自动映射到对应的OSError子类异常从而写出健壮、可移植的系统级错误处理代码。errno 模块是什么errno是 CPython 的一个内建标准模块作用是把操作系统底层的“errno 系统符号”原样暴露给 Python 层。每个符号对应的值就是操作系统使用的那个整数例如在大多数系统上errno.ENOENT等于整数2。模块本身不新增任何业务语义它是对平台 C 头文件errno.h中常量的一次系统化、按平台条件导出的镜像。从实现看该模块由 Modules/errnomodule.c 提供其模块文档字符串见 errnomodule.c明确说明了这一用途The value of each symbol is the corresponding integer value, e.g., on most systems,errno.ENOENTequals the integer 2. The dictionaryerrno.errorcodemaps numeric codes to symbol names...源码中的名称与英文注释“borrowed from linux/include/errno.h”见 errnomodule.c这一点与官方文档 errno.rst 中“names and descriptions are borrowed fromlinux/include/errno.h, which should be all-inclusive”的表述互相印证——即 errno 符号表设计上以 Linux 的 errno.h 为全集基准力求“包罗万象”同时兼顾 Solaris、macOS 等平台的独有符号。核心数据对象errorcode 字典errno模块中最重要的数据对象是errno.errorcode它是一个提供从 errno 整数值到字符串名称映射的字典。例如 import errno errno.errorcode[errno.EPERM] # 取 EPERM 对应的字符串名称 EPERM其用途与模块内的符号属性正好互补errno.EPERM属性访问——由符号名得到整数值errno.errorcode[errno.EPERM]字典查询——由整数值得到符号名字符串。在 C 实现中errno模块的表结构正是“一个模块属性字典 一个 errorcode 字典”双向插入构建的。核心逻辑位于 errnomodule.cstatic int _add_errcode(PyObject *module_dict, PyObject *error_dict, const char *name_str, int code_int) { ... /* insert in modules dict */ if (PyDict_SetItem(module_dict, name, code) 0) { ... } /* insert in errorcode dict */ if (PyDict_SetItem(error_dict, code, name) 0) { ... } ... }即每个符号通过add_errcode(ENOENT, ENOENT, No such file or directory)这样的宏见 errnomodule.c同时写入两处errno.errorcode则在模块执行入口errno_exec中先创建再填充见 errnomodule.c。该模块在标准库中的配套测试 Lib/test/test_errno.py 对errorcode字典做了两条一致性约束errorcode 完整性errorcode中每个字符串值都必须能作为属性存在于errno模块上见 test_errno.py属性双向覆盖模块__dict__中每一个全大写命名的属性其整数值也都必须能反向在errorcode字典中查到见 test_errno.py。这两条测试保证了“符号→数值→符号名”的双向查找永远不会断裂。平台条件导出并非所有符号在所有平台都可用官方文档 errno.rst 明确提醒在当前平台上未被使用的符号模块就不会定义。也就是说errno的成员集合随操作系统/编译环境变化同一份代码在不同平台看到的dir(errno)并不相同。具体有哪些符号可用可以通过下面两种方式查询import errno # 方式一errorcode 的键集合即当前平台定义的全部符号值 print(errno.errorcode.keys()) # 方式二直接列出模块中定义的全大写符号名 names [k for k in errno.__dict__ if k.isupper()] print(len(names), symbols defined on this platform)这种按平台裁剪的机制在源码中体现得十分直接C 代码中每个符号都包裹在条件编译#ifdef/#endif内例如#ifdef ENODEV、#ifdef EHOSTUNREACH见 errnomodule.c只有当前平台的系统头文件定义了该 errno 常量才会被注册进模块。因此在 Linux 上可看到完整的EPERM~ERFKILL及 Linux 特有的ELOCKUNMAPPED、ENOTACTIVE等macOS 额外携带EAUTH、EBADARCH、EBADEXEC、EBADMACHO、EBADRPC、EPROCLIM等“MacOSX specific errnos”见 errnomodule.cSolaris 平台补充ECANCELED、ENOTSUP、EOWNERDEAD、ENOTRECOVERABLE等“Solaris-specific errnos”见 errnomodule.cWASI 平台特有的ENOTCAPABLE“Capabilities insufficient”在有#ifdef ENOTCAPABLE时也会注册见 errnomodule.c。Windows 平台WSA 套接字错误码的桥接Windows 上errno.h与 Winsock 的错误码体系并不一致。为了让 Python 的 errno 符号保持跨平台一致语义源码在 MS_WINDOWS 分支下做了特殊处理见 errnomodule.c先#undef掉那些在 VS2010 之后才被塞进errno.h、但实际应优先使用 WSA 等价值的常量包括EADDRINUSE、ECONNRESET、ETIMEDOUT、EWOULDBLOCK等约 25 个随后在这些符号不存在于errno.h时改用对应WSAE*错误码来注册例如#ifdef EHOSTUNREACH add_errcode(EHOSTUNREACH, EHOSTUNREACH, No route to host); #else #ifdef WSAEHOSTUNREACH add_errcode(EHOSTUNREACH, WSAEHOSTUNREACH, No route to host); #endif #endif见 errnomodule.c。因此 Windows 上errno.EHOSTUNREACH的值实际来自 Winsock 的WSAEHOSTUNREACH从而保证 Python 层网络代码只需面对统一的 errno 命名。符号速查errno 成员及含义总表官方文档 errno.rst 给出了当前版本的完整符号列表。由于符号是按平台条件导出的下表中的可用性以当前平台为准可通过errno.errorcode.keys()实测。表中凡是文档标注了对应异常类型的条目CPython 在抛出该 errno 时会自动转换为相应的OSError子类详见下一节“异常自动映射”。通用核心符号几乎所有 POSIX 平台可用errno 符号整型值含义文档原文描述自动映射的内置异常EPERMOperation not permitted操作不被允许PermissionErrorENOENTNo such file or directory无此文件或目录FileNotFoundErrorESRCHNo such process无此进程ProcessLookupErrorEINTRInterrupted system call系统调用被中断InterruptedErrorEIOI/O errorI/O 错误—ENXIONo such device or address无此设备或地址—E2BIGArg list too long参数列表过长—ENOEXECExec format error可执行文件格式错误—EBADFBad file number文件描述符错误—ECHILDNo child processes无子进程ChildProcessErrorEAGAINTry again资源暂不可用请重试BlockingIOErrorENOMEMOut of memory内存不足—EACCESPermission denied权限被拒绝PermissionErrorEFAULTBad address非法地址—ENOTBLKBlock device required需要块设备—EBUSYDevice or resource busy设备或资源忙—EEXISTFile exists文件已存在FileExistsErrorEXDEVCross-device link跨设备链接—ENODEVNo such device无此设备—ENOTDIRNot a directory不是目录NotADirectoryErrorEISDIRIs a directory是目录IsADirectoryErrorEINVALInvalid argument参数无效—ENFILEFile table overflow系统文件表溢出—EMFILEToo many open files打开的文件过多—ENOTTYNot a typewriter不是终端设备—ETXTBSYText file busy文本文件正被占用—EFBIGFile too large文件过大—ENOSPCNo space left on device设备空间不足—ESPIPEIllegal seek非法定位—EROFSRead-only file system只读文件系统—EMLINKToo many links链接数过多—EPIPEBroken pipe管道破裂BrokenPipeErrorEDOMMath argument out of domain of func数学参数超出定义域—ERANGEMath result not representable数学结果无法表示—EDEADLKResource deadlock would occur将发生资源死锁—ENAMETOOLONGFile name too long文件名过长—ENOLCKNo record locks available无可用记录锁—ENOSYSFunction not implemented功能未实现—ENOTEMPTYDirectory not empty目录非空—ELOOPToo many symbolic links encountered符号链接层数过多—EWOULDBLOCKOperation would block操作会阻塞BlockingIOError消息队列 / 流 / STREAMS 相关符号errno 符号整型值含义备注ENOMSGNo message of desired type—EIDRMIdentifier removed—ECHRNGChannel number out of range—EL2NSYNCLevel 2 not synchronized—EL3HLTLevel 3 halted—EL3RSTLevel 3 reset—ELNRNGLink number out of range—EUNATCHProtocol driver not attached—ENOCSINo CSI structure available—EL2HLTLevel 2 halted—EBADEInvalid exchange—EBADRInvalid request descriptor—EXFULLExchange full—ENOANONo anode—EBADRQCInvalid request code—EBADSLTInvalid slot—EDEADLOCKFile locking deadlock error与EDEADLK语义相近EBFONTBad font file format—ENOSTRDevice not a stream—ENODATANo data available—ETIMETimer expired—ENOSROut of streams resources—ENONETMachine is not on the network—ENOPKGPackage not installed—EREMOTEObject is remote—ENOLINKLink has been severed—EADVAdvertise error—ESRMNTSrmount error—ECOMMCommunication error on send—EPROTOProtocol error—EMULTIHOPMultihop attempted—EDOTDOTRFS specific error—EBADMSGNot a data message—EOVERFLOWValue too large for defined data type—ENOTUNIQName not unique on network—EBADFDFile descriptor in bad state—EREMCHGRemote address changed—ELIBACCCan not access a needed shared library—ELIBBADAccessing a corrupted shared library—ELIBSCN.lib section in a.out corrupted—ELIBMAXAttempting to link in too many shared libraries—ELIBEXECCannot exec a shared library directly—EILSEQIllegal byte sequence非法字节序列—ERESTARTInterrupted system call should be restarted—ESTRPIPEStreams pipe error—EUSERSToo many users—网络 / 套接字相关符号errno 符号整型值含义自动映射的内置异常ENOTSOCKSocket operation on non-socket—EDESTADDRREQDestination address required—EMSGSIZEMessage too long—EPROTOTYPEProtocol wrong type for socket—ENOPROTOOPTProtocol not available—EPROTONOSUPPORTProtocol not supported—ESOCKTNOSUPPORTSocket type not supported—EOPNOTSUPPOperation not supported on transport endpoint—ENOTSUPOperation not supported3.2 起加入EPFNOSUPPORTProtocol family not supported—EAFNOSUPPORTAddress family not supported by protocol—EADDRINUSEAddress already in use地址已被占用—EADDRNOTAVAILCannot assign requested address—ENETDOWNNetwork is down—ENETUNREACHNetwork is unreachable—ENETRESETNetwork dropped connection because of reset—ECONNABORTEDSoftware caused connection abortConnectionAbortedErrorECONNRESETConnection reset by peer对端重置连接ConnectionResetErrorENOBUFSNo buffer space available—EISCONNTransport endpoint is already connected—ENOTCONNTransport endpoint is not connected—ESHUTDOWNCannot send after transport endpoint shutdownBrokenPipeErrorETOOMANYREFSToo many references: cannot splice—ETIMEDOUTConnection timed out连接超时TimeoutErrorECONNREFUSEDConnection refused连接被拒绝ConnectionRefusedErrorEHOSTDOWNHost is down—EHOSTUNREACHNo route to host—EALREADYOperation already in progressBlockingIOErrorEINPROGRESSOperation now in progressBlockingIOError文件系统高级特性 / 现代平台新增符号errno 符号整型值含义版本 / 平台备注ESTALEStale NFS file handleNFS 文件句柄失效NFS 相关EUCLEANStructure needs cleaning—ENOTNAMNot a XENIX named type file—ENAVAILNo XENIX semaphores available—EISNAMIs a named type file—EREMOTEIORemote I/O error—EDQUOTQuota exceeded磁盘配额超限—EQFULLInterface output queue is full3.11 起加入ENOMEDIUMNo medium found—EMEDIUMTYPEWrong medium type—ENOKEYRequired key not available—EKEYEXPIREDKey has expired—EKEYREVOKEDKey has been revoked—EKEYREJECTEDKey was rejected by service—ERFKILLOperation not possible due to RF-kill—ELOCKUNMAPPEDLocked lock was unmappedLinux 特有ENOTACTIVEFacility is not activeLinux 特有EAUTHAuthentication error3.2 起加入macOS/BSDEBADARCHBad CPU type in executable3.2 起加入macOSEBADEXECBad executable (or shared library)3.2 起加入macOSEBADMACHOMalformed Mach-o file3.2 起加入macOSEBADRPCRPC struct is bad3.2 起加入macOSEDEVERRDevice error3.2 起加入macOSEFTYPEInappropriate file type or format3.2 起加入ENEEDAUTHNeed authenticator3.2 起加入macOSENOATTRAttribute not found3.2 起加入macOSENOPOLICYPolicy not found3.2 起加入macOSEPROCLIMToo many processes3.2 起加入macOSEPROCUNAVAILBad procedure for program3.2 起加入macOSEPROGMISMATCHProgram version wrong3.2 起加入macOSEPROGUNAVAILRPC prog. not avail3.2 起加入macOSEPWROFFDevice power is off3.2 起加入macOSERPCMISMATCHRPC version wrong3.2 起加入macOSESHLIBVERSShared library version mismatch3.2 起加入macOSECANCELEDOperation canceled3.2 起加入EOWNERDEADOwner died3.2 起加入ENOTRECOVERABLEState not recoverable3.2 起加入ENOTCAPABLECapabilities insufficient3.11.1 起加入WASI、FreeBSDEHWPOISONMemory page has hardware error内存页硬件故障3.14 起加入各符号的.. versionadded::标注与其在源码中的注释一致3.11 引入EQFULL3.14 引入EHWPOISON3.11.1 引入 WASI/FreeBSD 专用的ENOTCAPABLE而 macOS/BSD 系列EAUTH至ECANCELED、EOWNERDEAD、ENOTRECOVERABLE等大多在 3.2 起随平台支持加入。errno 与 OSError 子类的自动映射文档中大量条目标注了“This error is mapped to the exception :exc:PermissionError”等映射说明这是errno模块最具工程价值的部分CPython 会在解释器内部维护 errno 整数值 →OSError子类的映射表errnomap当底层 C 调用因某个 errno 失败时Python 层抛出的不是笼统的OSError而是更具体的异常子类便于精细化except。该映射表在 Objects/exceptions.c 的_PyOSError_Init中通过ADD_ERRNO(TYPE, CODE)宏逐一建立与文档的标注一一对应errno映射到的异常子类异常含义EAGAIN/EALREADY/EINPROGRESS/EWOULDBLOCKBlockingIOError操作会阻塞非阻塞 I/O 场景EPIPE、ESHUTDOWN有定义时BrokenPipeError管道破裂/已关闭连接后发送ECHILDChildProcessError无子进程可等待ECONNABORTEDConnectionAbortedError连接被中止ECONNREFUSEDConnectionRefusedError连接被拒绝ECONNRESETConnectionResetError连接被对端重置EEXISTFileExistsError文件已存在ENOENTFileNotFoundError文件/目录不存在EISDIRIsADirectoryError目标是目录ENOTDIRNotADirectoryError不是目录EINTRInterruptedError系统调用被信号中断EACCES/EPERM、ENOTCAPABLE有定义时PermissionError权限不足ESRCHProcessLookupError进程不存在ETIMEDOUT含 WindowsWSAETIMEDOUTTimeoutError操作超时需要注意的工程要点映射仅对OSError本身生效。errnomap的查找逻辑位于 OSError 的类型初始化与构造路径见 Objects/exceptions.c只有以OSError(...)方式构造、并且 type 恰好是OSError时才会把errno数值“翻译”成最匹配的子类。而异常机制每次最终抛出时都会经过这一映射。errnomap是逐解释器interpreter独立的由struct _Py_exc_state持有见 Objects/exceptions.c多解释器环境下互不干扰。文档中“symbols available can include”是保守表述——最终以errno.errorcode.keys()实测结果为准切勿在代码里硬编码某个平台可能没有的符号如直接在 Windows 上依赖 Linux 的ELOCKUNMAPPED应先hasattr(errno, ELOCKUNMAPPED)判断。从数值错误码到异常/消息的完整翻译链路把三者串起来一次完整的“底层错误 → Python 异常”翻译链路是C 层系统调用失败后设置errno如ENOENT 2解释器依据 Objects/exceptions.c 的errnomap找到对应OSError子类FileNotFoundError并抛出若代码想拿到可读消息可用os.strerror(errno)。os.strerror(code)定义在 Doc/library/os.rst对应 C 的strerror()在未知错误码可能返回NULL的平台上会回退处理。import errno, os print(errno.ENOENT) # 2大多数系统 print(errno.errorcode[errno.ENOENT]) # ENOENT print(os.strerror(errno.ENOENT)) # No such file or directory随系统 locale官方文档强调把数值错误码翻译成错误消息应当使用os.strerror而不是errno模块本身——errno只负责“符号⇄数值”的映射消息文本由操作系统提供。实战用 errno 写出可移植的错误处理场景一区分“文件不存在”和“权限不足”import errno import os try: with open(/etc/shadow) as f: # 典型权限受限文件 print(f.read()) except PermissionError: print(没有权限读取该文件) except FileNotFoundError: print(文件不存在)这正是errnomap自动映射的价值你不需要每次比较e.errno errno.EACCESexcept PermissionError就能精准命中EACCES、EPERM引发的失败。场景二非阻塞 I/O 的“资源暂时不可用”判断网络编程中EAGAIN/EWOULDBLOCK非阻塞模式下暂时无数据可读在 CPython 中被统一映射为BlockingIOErrorimport errno import socket sock socket.socket() sock.setblocking(False) try: sock.connect((example.com, 80)) except BlockingIOError as e: # connect 尚未完成errno 可能是 EINPROGRESS / EALREADY if e.errno in (errno.EINPROGRESS, errno.EALREADY): print(连接进行中可交由事件循环稍后检查)场景三按 errno 数值做跨平台兜底当目标异常子类覆盖不全、或需要处理“无专有子类”的 errno如ENOSPC、ENOMEM时仍可退回检查e.errnoimport errno try: with open(/tmp/bigfile, wb) as f: f.write(b\0 * (10**12)) except OSError as e: if e.errno errno.ENOSPC: print(磁盘空间不足请清理后再试) elif e.errno errno.EDQUOT: print(超出磁盘配额) else: print(f其他 I/O 错误 errno{e.errno}: {e.strerror})跨平台前务必用hasattr做能力探测例如 WASI/FreeBSD 之外的平台没有ENOTCAPABLECAP getattr(errno, ENOTCAPABLE, None) if CAP is not None and e.errno CAP: print(capability 不足)场景四EINTR 中断后的自动重试EINTR系统调用被信号中断映射为InterruptedError。早期 Python 代码常需手动重试如今多数系统调用会自动重启但显式处理仍常见于信号密集的程序import errno import os while True: try: data os.read(fd, 4096) break except InterruptedError: continue # errno EINTR重试系统调用用errorcode反向查名输出可读日志记录日志时把数值还原为符号名便于排障阅读import errno def describe(e): code getattr(e, errno, None) if code is not None and code in errno.errorcode: return ferrno{code} ({errno.errorcode[code]}) {e.strerror} return repr(e) try: 1 / len([]) except OSError as e: print(describe(e)) # 例如errno13 (EACCES) Permission deniederrno 模块的构建与运行机制进阶从 Modules/errnomodule.c 可以进一步看到该模块在 CPython 内部的设计细节无方法、纯数据模块模块方法表errno_methods为空见 errnomodule.c全部内容都是初始化期写入的属性与字典使用多阶段初始化multi-phase init通过PyModuleDef_Slot声明Py_mod_exec钩子真正填表工作放在errno_exec中完成见 errnomodule.c从而支持子解释器场景自由线程free-threaded适配slot 表中显式声明了Py_mod_gil Py_MOD_GIL_NOT_USED表明该模块可在无 GIL 构建下安全运行模块在Py_GIL_DISABLED构建下不强制Py_LIMITED_API见 errnomodule.c单条代码路径双向插入_add_errcode同时维护“模块符号属性”和“errorcode 字典”从根上保证二者永不失配配套测试 Lib/test/test_errno.py 进一步守护这一不变式。总结errno模块虽小却是 CPython 打通“操作系统错误码 ↔ Python 层符号 ↔ OSError 异常子类”三方的关键枢纽符号⇄数值errno.EPERM与errno.errorcode[errno.EPERM]双向映射随平台条件导出见 Modules/errnomodule.c数值→消息交给os.strerror见 Doc/library/os.rst数值→异常子类由解释器内部errnomap见 Objects/exceptions.c完成让except FileNotFoundError、except PermissionError等写法成为可能。理解这三层关系后你写出的错误处理代码既能在 Linux/macOS/Windows/WASI 之间平滑移植又能准确、可读地向调用方表达失败原因——这正是标准库把操作系统细节“翻译”给 Python 程序员的完整故事。【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。