开发者

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

目录
  • 1. 变量到底是什么?
  • 2. 变量的底层实现:字节码
  • 3. 命名空间与作用域
  • 4. 不同变量的字节码
    • 4.1. 局部变量
    • 4.2. 全局变量
    • 4.3. 闭包变量
  • 5. 类中的变量
    • 6. 编译器如何选择指令
      • 7. 总结

        python中,变量的使用看起来非常简单,例如 a = 10s = "hello"等等。

        然而,这种简单的赋值操作背后,CPython其实做了很多复杂的工作。

        本文将通过一些简单易懂的代码示例,一起探索Python变量背后的奥秘,让我们对它的实现机制有更深一步的理解。

        1. 变量到底是什么?

        Python中,变量本质上是一个名字到值的映射。

        例如,当你写a = 1时,a是一个名字,而1是一个值。

        CPython会将这个名字关联起来,以便你后续可以通过名字访问这个

        a = 1
        print(a)  # 输出:1
        

        这种映射关系是通过一个名为命名空间的结构实现的。

        命名空间是一个字典,其中的键是变量名,值是变量对应的对象。

        它的定义可参考CPytpythonhon源码中的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, pythonmay be NULL. Only valid if not on C stack */
          编程客栈  /python/ 省略... ...
        }
        

        其中,f_locals 保存局部变量映射,函数执行时,局部变量值存于此;

        f_globals 用于全局变量,模块级代码块执行时,f_globals 指向模块全局命名空间字典;

        f_builtins 关联内置命名空间。

        2. 变量的底层实现:字节码

        CPython在执行代码时,会先将代码编译成字节码,然后由虚拟机执行这些字节码。我们可以通过 dis 模块查看代码的字节码。

        例如,对于a = 1,字节码如下:

        import dis
        
        code = """
        a = b
        """
        dis.dis(code)
        

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

        • LOAD_NAME:从命名空间中加载变量b的值
        • STORE_NAME:将值存储到变量a

        这两个指令展示了CPython如何处理变量的读取和赋值。

        3. 命名空间与作用域

        Python中的变量存储在不同的命名空间中,而这些命名空间又与代码的作用域相关,作用域决定了变量的可见性。

        Python有三种主要的作用域:

        • 局部作用域:函数内部的变量
        • 全局作用域:模块级别的变量
        • 内置作用域:包含内置函数和类型的命名空间
        x = "global"  # 全局变量
        
        def func():
            y = "local"  # 局部变量
            print(x)  # 输出:global
            print(y)  # 输出:local
        
        func()
        

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

        在这个例子中,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)
        

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

        4.2. 全局变量

        全局变量使用LOAD_GLOBALSTORE_GLOBAL指令。

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

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

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

        4.3. 闭包变量

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

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

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

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

        5. 类中的变量

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

        类定义中的变量使用LOAD_NAMESTORE_NAME指令,因为类的命名空间会动态地与全局命名空间交互。

        x = "global"
        
        class MyClass:
            print(x)  # 使用 LOAD_NAME
            x = "local"
            print(x)  # 使用 LOAD_NAME
        
        MyClass()
        

        输出:

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

        查看指令的话,可以使用: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变量的资料请关注编程客栈(www.devze.com)其它相关文章!

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜