论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
ToB企服应用市场:ToB评测及商务社交产业平台
»
论坛
›
软件与程序人生
›
后端开发
›
Java
›
『Python底层原理』--CPython的变量实现机制 ...
『Python底层原理』--CPython的变量实现机制
科技颠覆者
金牌会员
|
2025-2-19 22:38:38
|
显示全部楼层
|
阅读模式
楼主
主题
896
|
帖子
896
|
积分
2688
在Python中,变量的利用看起来非常简单,例如 a = 10,s = "hello"等等。
然而,这种简单的赋值操作背后,CPython其实做了许多复杂的工作。
本文将通过一些简单易懂的代码示例,一起探索Python变量背后的奥秘,让我们对它的实现机制有更深一步的理解。
1. 变量到底是什么?
在Python中,变量本质上是一个名字到值的映射。
例如,当你写a = 1时,a是一个名字,而1是一个值。
CPython会将这个
名字
和
值
关联起来,以便你后续可以通过
名字
访问这个
值
。
a = 1
print(a) # 输出:1
复制代码
这种映射关系是通过一个名为
命名空间
的布局实现的。
命名空间
是一个字典,其中的键是变量名,值是变量对应的对象。
它的界说可参考CPython源码中的Include/internal/pycore_frame.h文件。
typedef struct _PyInterpreterFrame {
// 省略... ...
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
// 省略... ...
}
复制代码
其中,f_locals 生存局部变量映射,函数执行时,局部变量值存于此;
f_globals 用于全局变量,模块级代码块执行时,f_globals 指向模块全局命名空间字典;
f_builtins 关联内置命名空间。
2. 变量的底层实现:字节码
CPython在执行代码时,会先将代码编译成字节码,然后由虚拟机执行这些字节码。我们可以通过 dis 模块检察代码的字节码。
例如,对于a = 1,字节码如下:
import dis
code = """
a = b
"""
dis.dis(code)
复制代码
LOAD_NAME:从命名空间中加载变量b的值
STORE_NAME:将值存储到变量a中
这两个指令展示了CPython如那边理变量的读取和赋值。
3. 命名空间与作用域
Python中的变量存储在不同的命名空间中,而这些命名空间又与代码的作用域相关,作用域决定了变量的可见性。
Python有三种重要的作用域:
局部作用域
:函数内部的变量
全局作用域
:模块级别的变量
内置作用域
:包含内置函数和类型的命名空间
x = "global" # 全局变量
def func():
y = "local" # 局部变量
print(x) # 输出:global
print(y) # 输出:local
func()
复制代码
在这个例子中,x是全局变量,y是局部变量。
如果在函数中尝试访问一个
未界说
的变量,CPython会按照以下顺序查找:
局部命名空间(f_locals)
全局命名空间(f_globals)
内置命名空间(f_builtins)
如果仍旧找不到,就会抛出NameError非常。
4. 不同变量的字节码
CPython为不同作用域的变量提供了不同的字节码指令,以优化性能和实现特定的行为。
4.1. 局部变量
在函数中,局部变量利用LOAD_FAST和STORE_FAST指令。
这些指令直接操作一个数组,而不是字典,因此速度更快。
def func():
a = 1 # STORE_FAST
b = a # LOAD_FAST
return b
dis.dis(func)
复制代码
4.2. 全局变量
全局变量利用LOAD_GLOBAL和STORE_GLOBAL指令。
这些指令会直接操作全局命名空间。
x = 1
def func():
global x
x = 2 # STORE_GLOBAL
return x # LOAD_GLOBAL
dis.dis(func)
复制代码
4.3. 闭包变量
当函数嵌套时,内部函数可以访问外部函数的变量。
这些变量称为
闭包变量
,利用LOAD_DEREF和STORE_DEREF指令。
def outer():
x = 1
def inner():
return x # LOAD_DEREF
return inner
dis.dis(outer)
复制代码
5. 类中的变量
在类界说中,变量的行为与函数不同。
类界说中的变量利用LOAD_NAME和STORE_NAME指令,因为类的命名空间会动态地与全局命名空间交互。
x = "global"
class MyClass:
print(x) # 使用 LOAD_NAME
x = "local"
print(x) # 使用 LOAD_NAME
MyClass()
复制代码
输出:
检察指令的话,可以利用:python.exe -m dis .\cpython-variable.py命令。
如果在类中利用嵌套函数,CPython会利用LOAD_CLASSDEREF指令来处理闭包变量。
class MyClass:
x = "cell"
def method(self):
print(x) # 使用 LOAD_CLASSDEREF
MyClass().method()
复制代码
6. 编译器如何选择指令
CPython的编译器会根据变量的作用域和代码块类型选择合适的字节码指令。
例如:
如果变量是局部变量,编译器会生成LOAD_FAST和STORE_FAST
如果变量是全局变量,编译器会生成LOAD_GLOBAL和STORE_GLOBAL
如果变量是闭包变量,编译器会生成LOAD_DEREF和STORE_DEREF
7. 总结
Python变量的实现机制比看起来复杂得多,它涉及到字节码指令、命名空间、作用域以及编译器的决议逻辑。
通过理解这些概念,可以更好地掌握Python的变量行为,尤其是在复杂的作用域场景中。
如果对CPython的实现感兴趣,可以进一步阅读其源码中与变量相关的部分。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
科技颠覆者
金牌会员
这个人很懒什么都没写!
楼主热帖
XAML 设计器已意外退出。(退出代码: e0 ...
OpenCV提取十字标中心点的几种思路 ...
我分析30w条数据后发现,西安新房公摊 ...
Windows | RDPWrap 远程桌面登录加强工 ...
码上加速,低代码解锁高效交付案例 ...
计算机网络学习—计算机网络概述 ...
SQLI-LABS(Less-7)
WPF 使用 MAUI 的自绘制逻辑
Cesium 案例(二)Web MapTile Service ...
K8S 实用工具之三 - 图形化 UI Lens ...
标签云
挺好的
服务器
快速回复
返回顶部
返回列表