网易首页 > 网易号 > 正文 申请入驻

Python:代码对象

0
分享至

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

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

一、什么是代码对象

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

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

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

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

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

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

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

代码对象不是:

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

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

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

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

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

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

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

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

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

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

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

以函数定义为例:

    

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

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

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

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

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

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

例如:

• 模块顶层代码

• 类体

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

• lambda 表达式

# True

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

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

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

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

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

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

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

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

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

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

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

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

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

• 一段代码 → 多次执行

• 一份结构 → 多个帧实例

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

从模型上可以概括为:

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

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

递归示例:

    

在该示例中:

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

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

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

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

多次调用示例:

inc(10)  # 11

这里同样是:

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

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

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

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

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

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

• 关联代码对象(__code__)

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

• 绑定默认参数

• 绑定闭包变量(如有)

type(f.__code__)    #

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

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

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

1、co_consts

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

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、代码对象视角下的闭包形成机制

考虑如下示例:

    

在编译阶段:

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

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

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

在执行阶段:

• 调用 outer 时创建帧对象

• x 被放入 cell 对象中

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

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

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

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

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

• 解释器执行复杂度激增

• 闭包语义不稳定

• 名称解析行为不可预测

因此 Python 选择:

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

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

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

小结

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

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


点赞有美意,赞赏是鼓励

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

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.

相关推荐
热点推荐
伊森状态低迷利于压价?均薪1800万以下可避硬帽:芬尼可用于交易

伊森状态低迷利于压价?均薪1800万以下可避硬帽:芬尼可用于交易

颜小白的篮球梦
2026-04-09 09:09:58
成龙72岁生日,带儿子房祖名惠州游玩,市长亲自陪同,父子感情好

成龙72岁生日,带儿子房祖名惠州游玩,市长亲自陪同,父子感情好

漫婷侃娱乐
2026-04-09 08:08:46
极有可能万斯会当上总统!对全世界都不是什么好事!因为万斯年轻

极有可能万斯会当上总统!对全世界都不是什么好事!因为万斯年轻

西楼知趣杂谈
2026-04-08 09:49:23
打起来了,美军开始“夺岛”?伊朗导弹密集发射,以色列不宣而战

打起来了,美军开始“夺岛”?伊朗导弹密集发射,以色列不宣而战

轩逸阿II
2026-04-09 09:20:46
又开打了!不是美军,不是以色列,阿联酋不宣而战,炸伊朗炼油厂

又开打了!不是美军,不是以色列,阿联酋不宣而战,炸伊朗炼油厂

军机Talk
2026-04-08 19:28:10
清明后湿气重,少喝水,多吃3种“祛湿菜”,健脾除湿,一身轻松

清明后湿气重,少喝水,多吃3种“祛湿菜”,健脾除湿,一身轻松

小茉莉美食记
2026-04-09 09:24:46
卡塔尔、科威特、巴林、阿联酋等多个海湾国家遭空袭

卡塔尔、科威特、巴林、阿联酋等多个海湾国家遭空袭

第一财经资讯
2026-04-09 08:23:50
73岁李立群再为全红婵发声:不指望她再为国夺金 她背后有高人指点

73岁李立群再为全红婵发声:不指望她再为国夺金 她背后有高人指点

喜欢历史的阿繁
2026-04-09 02:33:54
男子自驾游至海南遇美女搭车,同行三天后,他才知道自己逃过死劫

男子自驾游至海南遇美女搭车,同行三天后,他才知道自己逃过死劫

林林故事揭秘
2025-04-10 14:49:38
骑车过湘江两男子确认身亡,当时不顾劝阻硬闯后被冲走

骑车过湘江两男子确认身亡,当时不顾劝阻硬闯后被冲走

映射生活的身影
2026-04-08 10:43:45
具俊晔最新露面,又黑又瘦情绪低迷,在大S墓碑前静坐不语

具俊晔最新露面,又黑又瘦情绪低迷,在大S墓碑前静坐不语

素素娱乐
2026-04-09 08:53:34
演员陈学冬:11部作品被下架,两年4次手术,今35岁生活无法自理

演员陈学冬:11部作品被下架,两年4次手术,今35岁生活无法自理

以茶带书
2026-04-03 19:40:21
中国乒协:主动征询樊振东本人意见,其因个人原因自愿放弃伦敦世乒赛

中国乒协:主动征询樊振东本人意见,其因个人原因自愿放弃伦敦世乒赛

懂球帝
2026-04-08 20:15:04
欧冠战报:巴萨0-2马竞,库巴西红牌转折,巴黎2-0利物浦

欧冠战报:巴萨0-2马竞,库巴西红牌转折,巴黎2-0利物浦

许礆很机智
2026-04-09 09:30:39
樊振东自愿放弃!国乒公布世乒赛名单仅1小时 温瑞博落选原因曝光

樊振东自愿放弃!国乒公布世乒赛名单仅1小时 温瑞博落选原因曝光

生活新鲜市
2026-04-09 06:47:52
姚彬任武汉市副市长

姚彬任武汉市副市长

新京报
2026-04-08 19:23:12
山东旋转门家长已社死,信息被扒,官媒怒批,不止道歉这么简单!

山东旋转门家长已社死,信息被扒,官媒怒批,不止道歉这么简单!

阿凫爱吐槽
2026-04-09 05:08:54
弗里克:设置VAR到底是为了什么?这一点我真的想不通

弗里克:设置VAR到底是为了什么?这一点我真的想不通

懂球帝
2026-04-09 06:10:07
佩古拉谈纳达尔指导丝袜称是所有人的噩梦,凯斯打趣这应该被禁止

佩古拉谈纳达尔指导丝袜称是所有人的噩梦,凯斯打趣这应该被禁止

网球之家
2026-04-08 23:09:24
“一夜涨50万元,还谈个啥?”上海二手房市场现卖家大幅跳价,买家不干了

“一夜涨50万元,还谈个啥?”上海二手房市场现卖家大幅跳价,买家不干了

上观新闻
2026-04-06 22:10:08
2026-04-09 10:03:00
MediaTea
MediaTea
专业的数字媒体、新媒体技术
1826文章数 80关注度
往期回顾 全部

科技要闻

Meta凌晨首发闭源大模型 扎克伯格又行了?

头条要闻

福建45岁女子驾车坠河5人遇难有3名儿童 家属最新发声

头条要闻

福建45岁女子驾车坠河5人遇难有3名儿童 家属最新发声

体育要闻

40岁,但实力倒退12年

娱乐要闻

侯佩岑全家悉尼度假,一家四口幸福满溢

财经要闻

局势再升级!霍尔木兹海峡关闭

汽车要闻

20万级满配华为全家桶 华境S是懂家庭的大六座

态度原创

艺术
教育
数码
房产
手机

艺术要闻

赵丽颖再传喜讯,获央视点赞!网友:她的底气,藏不住了

教育要闻

一项30年数据研究:这3个专业读研恐出现负回报!

数码要闻

苹果自助维修商店更新 新增多款设备独立维修零件

房产要闻

超级卷王登场!海口首个抬板四代宅,彻底刷新认知!

手机要闻

OPPO Find X9s Pro手机外观曝光:四款配色,矩形相机模组

无障碍浏览 进入关怀版