news 2026/5/8 19:13:37

Python:代码对象

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python:代码对象

在 Python 的执行模型中,可执行代码并不是以字符串或抽象语法树的形式直接运行。源码在执行之前,会被编译为一种中间表示——代码对象(code object)。代码对象是 Python 对“可执行逻辑结构”的静态描述,是连接源码与运行期执行机制的关键枢纽。

在对象模型层面,代码对象并不负责执行,也不承载状态,而是作为一种描述对象,为后续的执行对象(函数对象、帧对象)提供结构蓝本。理解这一点,是正确理解函数、闭包、作用域以及调用机制的前提。

一、什么是代码对象

从概念上看,代码对象(code object)是对一段可执行 Python 代码结构的抽象描述。

代码对象并不保存源码文本,也不保存抽象语法树,而是描述:

• 这段代码将被编译成哪些字节码指令

• 执行时需要怎样的局部变量与参数布局

• 会使用到哪些字面量及编译阶段嵌入的字面量值对象

• 词法作用域关系如何建立

• 控制流(跳转、异常处理)应如何进行

代码对象不是:

• 函数对象(代码对象不可调用)

• 方法对象(代码对象不参与绑定)

• 帧对象(代码对象不保存局部变量、不维护指令指针)

这一定位决定了代码对象在整体模型中的角色:

代码对象负责描述执行结构,而不负责执行行为。

正是基于这一点,Python 在对象模型中明确区分了“描述对象”与“执行对象”,从而避免了结构描述与运行状态的混杂。

二、代码对象的产生:从源码到执行单元

当 Python 解释器处理一段源码时,会经历以下阶段:

1、解析(Parsing):源码 → 抽象语法树(AST)

2、编译(Compilation):AST → 代码对象

3、执行(Execution):执行对象引用代码对象 → 创建帧对象 → 解释执行字节码

以函数定义为例:

def add(a, b): return a + b

在函数定义语句被执行时:

1、函数体会先被编译为一个代码对象

2、随后解释器创建函数对象

3、函数对象持有该代码对象(通过 __code__ 属性)

更准确地说,在函数定义语句被执行的过程中,函数体对应的代码对象先被构造,随后才创建函数对象;函数对象只是对代码对象的一种执行语义封装。这一顺序在理解闭包、装饰器和函数动态构造时尤为重要。

需要说明的是,代码对象并不仅存在于函数中。事实上,在 Python 中凡是“可独立执行的代码块”,其编译结果都是代码对象。

例如:

• 模块顶层代码

• 类体

• 列表推导式、生成器表达式

• lambda 表达式

import types type((lambda x: x).__code__) is types.CodeType# True

这说明代码对象是 Python 执行模型中对可执行结构的基础抽象,而非函数的附属品。

三、对象协作:描述对象与执行对象的分层设计

在 Python 中,一次函数调用至少涉及三类对象:

• 代码对象:描述“执行结构”,被函数对象持有

• 函数对象:提供“可调用语义”,触发帧对象创建

• 帧对象:承载“运行期状态”,引用代码对象执行

这种分层并非实现巧合,而是对象模型层面的刻意设计。

1、为什么要区分“描述对象”与“执行对象”

如果将执行逻辑与运行状态混合在同一对象中,将直接导致以下问题:

• 同一段代码无法被多次、安全地复用

• 递归调用无法独立维护状态

• 闭包变量无法被可靠捕获

通过将代码对象设计为纯描述对象,Python 实现了:

• 一段代码 → 多次执行

• 一份结构 → 多个帧实例

• 一次定义 → 多种调用路径

从模型上可以概括为:

代码对象是“静态蓝本”,帧对象是“动态实例”。

下面通过递归与多次调用两个典型场景,具体说明这一分层为何不可或缺。

递归示例:

def fact(n): if n <= 1: return 1 return n * fact(n - 1)

在该示例中:

• fact 对应的代码对象只有一个

• 每一次递归调用都会创建一个新的帧对象

• 各帧对象分别保存各自的 n 值与执行位置

如果代码对象本身保存执行状态,递归调用将无法区分不同层级的执行上下文。

多次调用示例:

def inc(x): return x + 1 inc(1) # 2inc(10) # 11

这里同样是:

• 同一个代码对象被反复使用

• 每次调用生成独立的帧对象

• 调用之间不存在状态干扰

这说明,只有将“执行结构”与“执行状态”严格分离,代码的可重入性与可组合性才能成立。

2、代码对象与函数对象的关系

函数对象的职责,并不是保存代码结构,而是:

• 关联代码对象(__code__)

• 绑定全局命名空间(__globals__)

• 绑定默认参数

• 绑定闭包变量(如有)

def f(x): return x * 2 f.__code__ # 代码对象type(f.__code__) # <class 'code'>

同一个代码对象,理论上可以被多个函数对象共享,这也正是 types.FunctionType 能够存在的基础。

四、代码对象如何描述执行结构

代码对象内部包含大量只读字段,用于完整描述一段代码的执行形态。以下仅讨论与语义最直接相关的部分。

1、co_consts

co_consts 并非语言意义上的“常量表”,而是编译阶段嵌入字节码中的字面量值及嵌套代码对象的集合。

def f(): return 1 f.__code__.co_consts # (None, 1)

其中 None 对应编译器为函数体插入的隐式返回值字面量。

2、co_argcount 与 co_varnames

这两者共同描述参数与局部变量的布局方式。

• co_argcount:位置参数的数量

• co_varnames:局部变量名(包含参数)的元组

它们决定了帧对象中局部命名空间的槽位结构。

3、co_names

co_names 记录运行期需要通过名称解析的标识符,用于驱动全局查找与属性访问,例如:

• 全局变量名

• 内置函数名

• 属性名

解释器在执行相关字节码时,会通过该表进行名称解析。

4、co_cellvars 与 co_freevars

这两个字段用于支持闭包与词法作用域。

• co_cellvars:在本层定义、但被内层函数引用的变量

• co_freevars:来自外层作用域、被当前代码使用的自由变量

它们共同定义了变量如何被捕获并在多层函数调用中保持一致性。

五、执行关系:从代码对象到闭包与作用域

1、代码对象视角下的闭包形成机制

考虑如下示例:

def outer(x): def inner(y): return x + y return inner

在编译阶段:

• outer 的代码对象将 x 标记为 co_cellvars

• inner 的代码对象将 x 标记为 co_freevars

这一步完全发生在代码对象层面,尚未涉及任何运行时值。

在执行阶段:

• 调用 outer 时创建帧对象

• x 被放入 cell 对象中

• inner 函数对象持有对该 cell 的引用

由此可见,代码对象只负责声明“哪些变量需要被闭包捕获”,而不负责捕获行为本身。

捕获发生在函数对象与帧对象的协作中,而不是在代码对象中。

2、作用域为何必须在代码对象阶段确定

作用域关系一旦进入执行期再动态决定,将导致:

• 解释器执行复杂度激增

• 闭包语义不稳定

• 名称解析行为不可预测

因此 Python 选择:

• 在编译期由代码对象静态声明作用域结构

• 在运行期由帧对象动态承载具体值

这是“描述对象 vs 执行对象”分层设计在闭包机制中的直接体现。

📘 小结

代码对象在 Python 对象模型中承担的是“执行结构描述者”的角色,而非执行者本身。它在编译阶段确定代码的指令结构、变量布局与作用域关系,在运行期由函数对象与帧对象协同完成实际执行。

通过将代码对象设计为不可变的描述对象,并与执行对象严格分层,Python 实现了闭包、递归与高阶函数等机制的高度一致性与可组合性。理解代码对象,是理解 Python 执行语义与对象模型统一性的关键一环。

“点赞有美意,赞赏是鼓励”

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 19:00:25

curl-发送请求 和 tcpdump与wireshark的介绍

文章目录1.客户端模拟请求工具1.1. curl-终端/命令行请求工具常见用法1.2. curl重要参数1.3. curl其他常用参数2. tcpdump wireshark2.1 tcpdump参数说明参数&#xff1a;表达式&#xff1a;2.2 wireshark总结✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来&#xf…

作者头像 李华
网站建设 2026/5/1 17:43:39

14:00面试,14:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到5月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

作者头像 李华
网站建设 2026/5/8 14:43:38

python三大开发框架django、 flask 和 fastapi 对比

本文讲述了什么启发了 FastAPI 的诞生&#xff0c;它与其他替代框架的对比&#xff0c;以及从中汲取的经验。 如果不是基于前人的成果&#xff0c;FastAPI 将不会存在。在 FastAPI 之前&#xff0c;前人已经创建了许多工具 。 几年来&#xff0c;我一直在避免创建新框架。首先&…

作者头像 李华
网站建设 2026/5/1 10:15:20

微信小程序怎么测试

一、什么是小程序&#xff1f; 小程序是一种不需要下载安装即可使用的应用&#xff0c;它实现了应用“触手可及”的梦想&#xff0c;用户扫一扫或者搜一下即可打开应用。也体现了“用完即走”的理念&#xff0c;用户不用关心是否安装太多应用的问题。应用将无处不在&#xff0…

作者头像 李华
网站建设 2026/5/8 2:26:22

SAM3模型来了,手把手带你运行SAM3模型代码,SAM3模型初探!

SAM3模型简介 SAM3&#xff08;Segment Anything Model 3&#xff09;是Meta推出的第三代通用图像分割模型&#xff0c;具备零样本迁移能力&#xff0c;支持多模态输入&#xff08;如图像、文本提示&#xff09;。相比前代&#xff0c;SAM3在精度、速度和交互方式上均有显著提…

作者头像 李华
网站建设 2026/5/6 6:21:03

超轻量SAM模型部署:ONNX量化与Transformer剪枝全攻略

以下是超轻量SAM模型部署的技术方案&#xff0c;涵盖ONNX量化与Transformer剪枝的完整实施流程&#xff1a;ONNX动态量化实践导出基础ONNX模型python scripts/export_onnx_model.py \--checkpoint sam_vit_b_01ec64.pth \--model-type vit_b \--output sam_vit_b.onnx \--opset…

作者头像 李华