一文探索CPython的变量实现机制

 更新时间:2025年02月20日 08:18:11   作者:wang_yb  
在Python中,变量的使用看起来非常简单,然而,这种简单的赋值操作背后,CPython其实做了很多复杂的工作,下面我们就来一起探索一下吧

Python中,变量的使用看起来非常简单,例如 a = 10s = "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_FASTSTORE_FAST指令。

这些指令直接操作一个数组,而不是字典,因此速度更快。

def func():
    a = 1  # STORE_FAST
    b = a  # LOAD_FAST
    return b

dis.dis(func)

4.2. 全局变量

全局变量使用LOAD_GLOBALSTORE_GLOBAL指令。

这些指令会直接操作全局命名空间。

x = 1

def func():
    global x
    x = 2  # STORE_GLOBAL
    return x  # LOAD_GLOBAL

dis.dis(func)

4.3. 闭包变量

当函数嵌套时,内部函数可以访问外部函数的变量。

这些变量称为闭包变量,使用LOAD_DEREFSTORE_DEREF指令。

def outer():
    x = 1
    def inner():
        return x  # LOAD_DEREF
    return inner

dis.dis(outer)

5. 类中的变量

在类定义中,变量的行为与函数不同。

类定义中的变量使用LOAD_NAMESTORE_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_FASTSTORE_FAST
  • 如果变量是全局变量,编译器会生成LOAD_GLOBALSTORE_GLOBAL
  • 如果变量是闭包变量,编译器会生成LOAD_DEREFSTORE_DEREF

7. 总结

Python变量的实现机制比看起来复杂得多,它涉及到字节码指令、命名空间、作用域以及编译器的决策逻辑。

通过理解这些概念,可以更好地掌握Python的变量行为,尤其是在复杂的作用域场景中。

如果对CPython的实现感兴趣,可以进一步阅读其源码中与变量相关的部分。

以上就是一文探索CPython的变量实现机制的详细内容,更多关于CPython变量的资料请关注脚本之家其它相关文章!

相关文章

  • Python 自制简单版《我的世界》的详细过程

    Python 自制简单版《我的世界》的详细过程

    这篇文章主要介绍了教你用 Python 自制简单版《我的世界》,接下来,我们就带你运行这个项目,并对这个开源的小游戏做一下简单的更改,让它变成“你的”世界
    2021-11-11
  • Python爬虫抓取论坛关键字过程解析

    Python爬虫抓取论坛关键字过程解析

    这篇文章主要介绍了Python爬虫抓取论坛关键字过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Python中运行并行任务技巧

    Python中运行并行任务技巧

    这篇文章主要介绍了Python中运行并行任务技巧,本文给出了两个示例,并用map来处理并行任务,需要的朋友可以参考下
    2015-02-02
  • Python3中的真除和Floor除法用法分析

    Python3中的真除和Floor除法用法分析

    这篇文章主要介绍了Python3中的真除和Floor除法用法,结合实例形式分析了真除与Floor除法的区别与使用技巧,需要的朋友可以参考下
    2016-03-03
  • Python应用领域和就业形势分析总结

    Python应用领域和就业形势分析总结

    在本篇文章总我们给大家整理了关于Python应用领域和就业形势分析以及图文介绍,需要的朋友们可以参考下。
    2019-05-05
  • 使用PyTorch处理多维特征输入数据的完美实现

    使用PyTorch处理多维特征输入数据的完美实现

    在机器学习和深度学习领域,我们经常会面对具有多维特征输入的问题,这种情况出现在各种应用中,包括图像识别、自然语言处理、时间序列分析等,PyTorch是一个强大的深度学习框架,在本篇博客中,我们将探讨如何使用PyTorch来处理多维特征输入数据
    2023-10-10
  • python 生成任意形状的凸包图代码

    python 生成任意形状的凸包图代码

    这篇文章主要介绍了python 生成任意形状的凸包图代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • python获取当前目录路径和上级路径的实例

    python获取当前目录路径和上级路径的实例

    下面小编就为大家分享一篇python获取当前目录路径和上级路径的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • Python 迭代器工具包【推荐】

    Python 迭代器工具包【推荐】

    迭代器工具在产生数据的时候将会显得非常便捷、高效,掌握了这些基本的方法之后,通过简单的组合就可以获得更多迭代器工具。
    2016-05-05
  • python multiply()与dot使用示例讲解

    python multiply()与dot使用示例讲解

    这篇文章主要介绍了python multiply()与dot使用示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-12-12

最新评论