Python:帧对象

在 Python 的执行模型中,用于承载“一次具体执行过程”的,是另一类运行期对象——帧对象(frame object)。如果说代码对象描述了“应用如何执行”,那么帧对象承载的就是该执行在运行期展开时的具体状态。

从对象模型的角度看,帧对象是一类专门用于承载执行期状态的对象。它在调用发生时被创建,在执行结束后被销毁,负责保存局部变量、指令执行位置以及与调用链相关的上下文信息。理解帧对象,是理解函数调用、递归、异常传播、作用域解析乃至调试机制的关键。

一、什么是帧对象

帧对象(frame object)表示一次正在进行或已经发生的代码执行过程。每当一段代码被执行,解释器都会为其创建一个新的帧对象,用于记录该次执行所需的全部运行期状态。

从概念上看,帧对象负责描述:

• 当前正在执行的是哪一段代码(引用代码对象) 

• 局部命名空间与全局命名空间的绑定情况 

• 当前字节码指令执行到的位置 

• 与上层调用者之间的调用关系

帧对象不是:

• 代码对象(帧对象不描述执行结构) 

• 函数对象(帧对象不提供可调用语义) 

• 闭包对象(帧对象并不独立保存被闭包捕获的变量)

在对象模型中,帧对象的核心职责只有一个:承载“一次执行”的全部运行期状态。

二、帧对象的产生:从调用到执行上下文

帧对象并不是在编译阶段产生的,而是在运行期、调用发生时动态创建的。

当解释器执行一段可调用对象时,大致会经历如下过程:

1、确定被调用的函数对象 

2、从函数对象中取得其关联的代码对象 

3、基于代码对象创建新的帧对象 

4、初始化帧对象中的运行期状态 

5、进入字节码解释循环

以最简单的函数调用为例:

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

在执行 add(1, 2) 时:

• add 对应的代码对象并未发生变化 

• 解释器创建了一个新的帧对象 

• 参数 a、b 被写入该帧对象的局部命名空间 

• 指令指针从代码对象的起始位置开始推进

需要强调的是,同一个代码对象,可以在不同时间、不同调用路径下,对应多个不同的帧对象。

三、对象协作:代码对象、函数对象与帧对象

在 Python 的执行模型中,这三类对象分工明确、彼此协作:

• 代码对象:描述“如何执行” 

• 函数对象:提供“可调用入口” 

• 帧对象:承载“正在执行”

这种分层结构保证了执行模型的可重入性与一致性。

1、为什么帧对象必须是独立对象

如果将运行期状态直接存放在函数对象或代码对象中,将会立即破坏以下性质:

• 多次调用的相互独立性 

• 递归调用的正确性 

• 并发或协程切换时的状态隔离

帧对象作为独立的执行对象,则可使得:

• 每一次调用都有独立的执行上下文 

• 同一函数可被安全地重入调用 

• 调用链可以被精确地表示和回溯

从模型上可以概括为:代码对象是“静态蓝本”,帧对象是“动态实例”。

2、递归与多次调用示例

(1)递归示例

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

在该递归过程中:

• fact 的代码对象始终只有一个 

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

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

正是由于帧对象彼此独立,递归调用才能正确展开并回溯。

(2)多次调用示例

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

这里同样体现出:

• 代码结构被复用 

• 执行状态不共享

四、帧对象的核心运行期字段

帧对象内部保存了大量与执行直接相关的信息,其中最关键的包括以下部分。

1、代码对象引用(f_code)

f_code 指向当前执行的代码对象。它定义了:

• 字节码指令序列 

• 局部变量布局 

• 作用域与闭包结构

帧对象并不复制这些信息,而是直接引用代码对象。

2、局部命名空间(f_locals)

f_locals 保存当前执行上下文中的局部命名空间。

def f():    a = 1    b = 2    return a + b

在执行过程中,该帧的局部命名空间会动态变化。

需要注意的是,f_locals 是对当前局部变量状态的一种映射表示,其更新时机受解释器控制,并非实时字典。

3、全局命名空间(f_globals)

f_globals 指向函数或代码对象所属的全局命名空间,通常是模块的 __dict__

名称解析(LEGB)过程中,解释器正是通过 f_locals 和 f_globals 这两个映射结构完成查找。

4、当前指令位置(f_lasti)

f_lasti 表示当前正在执行或即将执行的字节码指令位置。该字段使得:

• 异常回溯成为可能 

• 调试器能够暂停与恢复执行 

• 解释器可以正确处理跳转与返回

这也是调试器、追踪器能够“暂停”、“单步执行”的根本依据。

5、上一帧引用(f_back)

f_back 指向调用该帧的上一个帧对象,形成调用栈链表结构:

当前帧 → f_back → 调用者帧 → …

这一链式结构构成了调用栈(call stack)。

通过 f_back,解释器能够:

• 构建完整的调用栈 

• 实现异常向上传播 

• 支持 traceback 机制

五、帧对象视角下的作用域与闭包

1、帧对象如何承载作用域

作用域的结构关系在编译阶段已由代码对象静态确定,但具体变量的取值与可见性,必须在运行期由执行上下文来承载。在 Python 中,这一职责由帧对象在运行期承担。

考虑如下示例:

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

在执行 outer(10) 时,解释器会经历如下过程:

• 创建 outer 对应的帧对象 

• 参数 x 被写入该帧的局部命名空间 

• 由于 x 被内层函数 inner 引用,解释器并不将其作为普通局部变量处理,相应地,x 被提升为 cell 对象承载的自由变量

outer 的帧对象不再直接保存 x 的值,而是保存对该 cell 的引用。

当 inner 被返回并随后调用时:

• 解释器为 inner 创建新的帧对象

• inner 的帧对象并不访问 outer 的帧对象,而是通过自身结构中保存的 cell 引用,间接读取 x 的值

由此可以看出,作用域在对象模型中的分工是清晰而分层的:

• 代码对象:声明作用域的结构关系

• 帧对象:承载一次执行中的局部状态

• cell 对象:承载可跨帧存续的自由变量值

帧对象并不是闭包变量的最终所有者,而是闭包语义得以建立的运行期中介。

2、帧对象与闭包生命周期

在函数返回后,其对应的帧对象通常会从调用链中移除,并在不再被引用时被销毁。但在闭包场景中,这一过程存在一个重要的例外。

当帧对象中的某些局部变量被提升为 cell 对象,并被闭包函数对象所引用时:

• 闭包函数对象会持有对 cell 的引用 

• cell 对象继续保存相关变量的值

因此,被延长生命周期的并不是帧对象本身,而是帧对象中被提取出的 cell 对象。

这种设计使得 Python 能够:

• 精确保留闭包所需的最小运行期状态

• 避免无谓地延长整个执行上下文的生命周期

• 在执行模型与内存管理之间取得良好平衡

正是通过帧对象负责执行、cell 对象负责延续的协作机制,Python 将闭包这一语义特性完整地映射进了对象模型之中。

六、帧对象的销毁与执行结束

当一段代码执行完毕后,帧对象从调用栈中弹出。若不再被任何对象引用,将被垃圾回收。

在以下情况下,帧对象可能被暂时保留:

• 异常尚未被处理(用于 traceback) 

• 调试器主动保存执行上下文 

• 闭包间接引用了其中的 cell

这再次体现了帧对象作为“执行期状态载体”的核心定位。

📘 小结

帧对象是 Python 执行模型中对“一次具体执行过程”的对象化表达。它在运行期动态创建,承载局部状态、执行位置与调用关系,并通过与代码对象和函数对象的协作,支撑起函数调用、递归、异常传播与闭包等核心机制。

通过将执行状态集中于帧对象,而将执行结构交由代码对象描述,Python 在对象模型层面实现了执行语义的清晰分层。这一设计,是 Python 执行模型高度一致性与可组合性的关键基础。

图片

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

Read more

从零开始使用ISSACLAB训练自己的机器人行走

从零开始使用ISSACLAB训练自己的机器人行走

ISAACLAB入门教程 作者:陈维耀 1. 环境配置 1.1 推荐配置 * 操作系统: Ubuntu 22.04 LTS * 显卡: NVIDIA RTX 4080或以上 1.2 ubuntu 22.04 LTS安装 参考ZEEKLOG的Ubuntu 16.04 LTS安装教程,将其中的ubuntu 16.04镜像文件替换为ubuntu 22.04镜像文件,其他步骤保持不变,建议/home与/usr的硬盘容量均不少于200G。 1.3 安装NVIDIA驱动 根据自身显卡型号与操作系统,选择对应的显卡驱动,建议选择550.xxx.xxx版本的显卡驱动,按照教程进行安装即可,安装完成后在终端输入nvidia-smi,若出现以下信息则表示驱动安装成功: Thu Jun 5

By Ne0inhk
最新 neo4j 5.26版本下载安装配置步骤(新手必备)

最新 neo4j 5.26版本下载安装配置步骤(新手必备)

目录 初识:neo4j 安装环境要求 一、下载Neo4j 二、配置环境变量 三、启动测试 四、常用命令及配置 创作不易,禁止转载抄袭!!!违者必究!!! 创作不易,禁止转载抄袭!!!违者必究!!! 创作不易,禁止转载抄袭!!!违者必究!!! 初识:neo4j Neo4j是一个高性能的NoSQL图形数据库,它将结构化数据存储在网络(从数学角度称为图)上而不是传统的表中。‌ Neo4j是一个嵌入式的、基于磁盘的、具备完全事务特性的Java持久化引擎,特别适合处理具有复杂关系的数据‌。 安装环境要求 * 操作系统:Windows 10/8/7、macOS 10.13或更高版本、Linux(Ubuntu、CentOS、Red Hat 等) * JDK 17 或更高版本(Neo4j

By Ne0inhk
【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

VR音游音符轨道系统开发实录与原理解析 在 VR 音游的开发过程中,音符轨道系统是最核心的交互与可视化部分。本文结合一次完整的开发实录,分享从核心原理与设计到VR内容构建的完整过程,帮助读者快速理解音符轨道系统的实现思路。 文章目录 * VR音游音符轨道系统开发实录与原理解析 * 一、实录结果 * 二、VR内容开发步骤 * 1. 准备音符与交互逻辑 * 2. 创建谱面 * 3. 绘制音轨 * 4. 预制件与音频替换 * 三、原理解析(音符轨道系统) * 1. 音符轨道(Note Track) * 2. 轨迹调节与偏移控制 * 3. 音符触摸激活 * 4. 谱面编辑工具(Editor 功能) * 四、总结与展望 * 1. 成果回顾:从零到一的核心突破 * 2. 技术总结:核心设计理念 * 3. 开发难点与问题反思 * 4. 优化策略与改进方向 * 5.

By Ne0inhk
医疗连续体机器人模块化控制界面设计与Python库应用研究(下)

医疗连续体机器人模块化控制界面设计与Python库应用研究(下)

软件环境部署 系统软件架构以实时性与兼容性为核心设计目标,具体配置如下表所示: 类别配置详情操作系统Ubuntu 20.04 LTS,集成RT_PREEMPT实时内核补丁(调度延迟<1 ms)开发环境Python 3.8核心库组件PyQt5 5.15.4(图形界面)、OpenCV 4.5.5(图像处理)、NumPy 1.21.6(数值计算) 该环境支持模块化控制界面开发与传感器数据的实时融合处理,为连续体机器人的逆运动学求解(如FB CCD算法测试)提供稳定运行基础[16]。 手眼协调校准 为实现视觉引导的精确控制,需完成相机与机器人基坐标系的空间映射校准,具体流程如下: 1. 标识点布置:在机器人末端及各段首尾、中间位置共固定7个反光标识点,构建臂型跟踪特征集[29]; 2. 数据采集:采用NOKOV度量光学动作捕捉系统(8台相机,

By Ne0inhk