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

【大数据存储与管理】分布式文件系统HDFS:07 HDFS编程实践

【大数据存储与管理】分布式文件系统HDFS:07 HDFS编程实践

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈大数据技术原理与应用 ⌋ ⌋ ⌋专栏系统介绍大数据的相关知识,分为大数据基础篇、大数据存储与管理篇、大数据处理与分析篇、大数据应用篇。内容包含大数据概述、大数据处理架构Hadoop、分布式文件系统HDFS、分布式数据库HBase、NoSQL数据库、云数据库、MapReduce、Hadoop再探讨、数据仓库Hive、Spark、流计算、Flink、图计算、数据可视化,以及大数据在互联网领域、生物医学领域的应用和大数据的其他应用。 【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/BigData_principle_application。 文章目录 * 一、HDFS常用命令 * 二、HDFS的Web页面 * 三、HDFS常用Java API及应用实例 * (一)常用Java API介绍 * (二)应用实例 * 总结

By Ne0inhk

Python GIS 脚本编程(四)

原文:zh.annas-archive.org/md5/14eca96eb97dc47d28f8de5385dca806 译者:飞龙 协议:CC BY-NC-SA 4.0 第十四章:云地理数据库分析和可视化 本章将介绍 CARTOframes,这是一个由位置智能软件公司 CARTO 于 2017 年 11 月发布的 Python 包。它提供了一个 Python 接口来处理 CARTO 栈,使 CARTO 地图、分析和数据服务能够集成到数据科学工作流程中。 本章将涵盖以下主题: * CARTOframes Python 库的详细信息 * 熟悉 CARTO 栈以及 CARTOframes 如何与它的不同部分交互 * 如何安装 CARTOframes、其包依赖项和文档 * CARTOframes 的不同包依赖项 * 如何获取

By Ne0inhk

Python 数据可视化秘籍(一)

原文:Python Data Visualization Cookbook 协议:CC BY-NC-SA 4.0 零、前言 最好的数据是我们能看到和理解的数据。作为开发人员,我们希望创建和构建最全面、最容易理解的可视化。它并不总是简单的;我们需要找到数据,阅读它,清洗它,按摩它,然后使用正确的工具来可视化它。这本书解释了如何用简单明了的方法来阅读、清理数据并将其可视化为信息的过程。 如何读取本地数据、远程数据、CSV、JSON 以及关系数据库中的数据,这本书都有讲解。 使用 matplotlib 可以在 Python 中用简单的一行代码绘制一些简单的图表,但是做更高级的图表需要的知识不仅仅是 Python。我们需要理解信息论和人类感知美学来产生最吸引人的视觉化。 这本书将解释 Python 中 matplotlib 绘图背后的一些实践,使用的统计数据,以及我们应该以最佳方式使用的不同图表功能的使用示例。 这本书是用 Python 2.7、IPython

By Ne0inhk
Python:wxauto无法安装的问题解决

Python:wxauto无法安装的问题解决

一、问题描述 我们在实现自动化发送微信消息的功能,需要wxauto工具包。 但是,现在直接pip install wxauto无法下载。 二、解决办法 直接上github下载源码使用。 https://github.com/cluic/wxauto/tree/main# 三、使用教程 下载源码后,直接用pycharm打开 新建test目录,新建test.py文件 从example.md文件中拷贝案例代码测试即可。 example.md案例 1. 基本使用 from wxauto import WeChat # 初始化微信实例 wx = WeChat()# 发送消息 wx.SendMsg("你好", who="张三")# 获取当前聊天窗口消息 msgs

By Ne0inhk