登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
博客
发1篇日志+1圆
记录
发1条记录+2圆币
发帖说明
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
VIP网盘
VIP申请
网盘
联系我们
道具
勋章
任务
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
业界
›
『Python底层原理』--CPython的变量实现机制 ...
『Python底层原理』--CPython的变量实现机制
[ 复制链接 ]
膏包
2025-6-9 10:48:31
在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的实现感兴趣,可以进一步阅读其源码中与变量相关的部分。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
签约作者
程序园优秀签约作者
发帖
膏包
2025-6-9 10:48:31
关注
0
粉丝关注
11
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
敖可
9984
黎瑞芝
9990
杭环
9988
4
猷咎
9988
5
凶契帽
9988
6
接快背
9988
7
氛疵
9988
8
恐肩
9986
9
虽裘侪
9986
10
里豳朝
9986
查看更多