在 Python 中,函数是“一等对象”,它们不仅仅包含可调用的逻辑,还携带大量由解释器维护的内部状态。其中最核心的结构之一,就是函数的 __code__ 属性。
__code__ 是一个code object(代码对象),包含了执行所需的所有静态信息:字节码、局部变量表、常量表、闭包变量、行号表、运行栈需求等。
理解 code object 是深入掌握 Python 执行模型的重要一步。
一、__code__ 是什么?
当 Python 执行一个 def 时,发生三件事:
• 源代码被编译成 bytecode(字节码)
• 字节码被封装为一个 code object(代码对象)
• 代码对象再被包在一个 function object(函数对象)中
结构示意:
源代码 → code object → function object因此:
• __code__ 是函数的“可执行内核”
• 函数本身只是对 code object 的一层包装(包含名字、默认值、注解、闭包等)
示例:
print(type(f.__code__))输出:
重点特性:
(1)code object 是不可变的(immutable)。
(2)但可以利用 types.CodeType() 创建新的 code 对象来替换函数的 __code__。
(3)Python 3.11+ 中 code object 内部结构大幅修改(但属性接口基本保持兼容)。
二、__code__中包含哪些信息
__code__ 记录了函数执行所需的全部静态信息,主要分为四类。
(1)参数与变量信息
属性名
含义
co_argcount
位置参数数量
co_posonlyargcount
仅限位置参数数量(3.8+)
co_kwonlyargcount
仅关键字参数数量
co_varnames
所有局部变量名(包含参数)
co_nlocals
局部变量数量
示例:
print(test.__code__.co_nlocals) # 3提示:
若需要所有局部变量名,不要只看 co_varnames,而应合并 co_varnames + co_cellvars。这是实践中常见的做法。
(2)名称解析相关
属性名
含义
co_names
函数体内引用的全局变量、属性名等
co_consts
常量表(字面量、内部函数 code 对象等)
co_qualname
函数的完整名称(含类名等)
示例:
print(f.__code__.co_consts) # (None, 1)注意:
co_consts[0] 通常是 None(函数隐式返回 None)。
(3)闭包结构
属性名
含义
co_freevars
当前函数中使用,但定义在外层作用域的变量
co_cellvars
当前函数中定义,并被内部函数引用的变量
示例:
print("inner.co_cellvars:", fn.__code__.co_cellvars)输出:
inner.co_cellvars: ()解释:
名称
在 outer 中
在 inner 中
归类
a
参数,被 inner 使用 → cellvar
来自外层 → freevar
cellvar + freevar
b
局部变量,被 inner 使用 → cellvar
来自外层 → freevar
cellvar + freevar
c
局部变量,被 inner 使用 → cellvar
来自外层 → freevar
cellvar + freevar
inner
outer 的局部变量,但未被捕获
只在 outer.co_varnames
简要说明:
• cellvars:我定义,内部函数你使用
• freevars:我使用,外层函数定义
(4)字节码与执行元信息
属性名
含义
co_code
字节码(3.11 前单纯的 bytecode,3.11+ 结构变化但属性仍存在)
co_firstlineno
函数起始行号
co_stacksize
执行时需要的栈大小
co_flags
标志位(是否为生成器、是否包含 varargs 等)
co_linetable/ co_exceptiontable
(3.11+)行号表与异常表
(5)Python 3.11+ 的新结构
从 3.11 开始,字节码结构发生重大变化:
新增 co_exceptiontable(替代旧行号表处理异常)
新增 co_linetable(替代 co_lnotab)
字节码采用 adaptive bytecode(动态优化的自适应字节码)
三、__code__与字节码
一个函数最终执行的是字节码(bytecode),可以使用 dis 模块查看。
示例:
dis.dis(f)输出(示例):
6 RETURN_VALUEPython 3.11 的字节码更加复杂(adaptive),但 code object 属性仍提供统一访问入口。
四、__code__的生命周期
(1)函数定义时创建(def 执行就生成 code 对象)。
(2)__code__ 是不可变的(保证执行安全)。
(3)多个函数可能共享同一个 __code__。
例如:
print({id(fn.__code__) for fn in lst})这些 lambda 会共享同一 code 对象。
(4)重新定义同名函数会创建新的 code 对象。
(5)无引用时由 GC 自动回收。
五、修改__code__
由于 __code__ 可被赋值,我们可以动态改变函数行为,这属于 Python 的元编程能力:
print(f()) # 999注意事项:
• 参数数量必须一致,否则抛 ValueError
• freevars/cellvars 数量必须一致
• 适用于调试器、框架、元编程,不建议在业务代码中使用
小结
__code__ 是 Python 函数的可执行核心,记录了字节码、局部变量、常量表、闭包结构、行号表等全部静态信息。
函数只是对 code object 的包装,而 code object 在函数定义时由编译器生成,并在运行期间保持不可变。通过 co_freevars 和 co_cellvars 可以理解闭包如何捕获外层变量,通过 co_code 和 dis 可以了解 Python 的执行模型,而在必要时替换 __code__ 还能动态改变函数行为。
![]()
“点赞有美意,赞赏是鼓励”
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.