# 作用域、名字空间、属性空间

# 作用域

  • 我们称一个名字能影响的区域为名字的作用域

  • 在Python中,作用域是静态的,也叫词法作用域-即使由名字引入的位置决定的,而不是运行时动态决定的

  • Python在编译时,根据语法规则将代码划分为不同的代码块,每个代码块形成一个作用域。

    • 整个.py文件形成全局作用域,也叫模块作用域
    • 遇到函数定义,函数体称为当前作用域的子作用域,并且函数作用域对子作用域是可见的
    • 遇到类定义,类定义体称为当前作用域的子作用域,但是类作用域对于子作用域是不可见的
    • 在当前作用域和全局作用域之间的部分统称为闭包作用域,一般是闭包函数才会出现这种情况
    g = 1
    
    def fun():
        fv = 2
    
    def outer():
        out = 3
        def inner():
            inn = 4
        return inner
    
    class C:
        c = 1
    
        def __init__(self) -> None:
            pass
    
        def cfun(self):
            print(g) # OK
            print(c) # WRONG
    
    def fun2():
        f2 = 5
    
        class CC:
            def __init__(self) -> None:
                pass
    
            def ccfun(self):
                print(f2) # OK
    

# 命名空间LEGB

  • 命名空间负责存储名字和对象的绑定关系,由于名字绑定关系是有 名字对象 组成的键值对,因而 dict 对象是理想的存储容器。

  • (G)每个模块背后都有一个dict对象(__dict__​​)表示全局名字空间,用于存储全局作用域的绑定关系

    • 注意Python中全局名字空间以模块为单位进行划分,而非全局统一

    • 模块的属性空间和全局名字空间实质是同一个对象 - __dict__​​​

      属性空间表示对象可以访问到的属性

  • (L)局部名字空间用于存储作用域内的绑定关系

  • (E)在作用域存在嵌套的情况下, Python 将内层代码块中依赖的所有外层名字存储在一个容器内,即 闭包名字空间 ( Enclosings )

  • (B)Python中还存在一个内键名字空间,其中提供了许多内键函数(例如print)或类型(例如int)

  • 在Python调用函数时,需要的上下文实际上就由这四个命名空间组成,查找顺序依次为LEGB

    image

# 属性空间

  • Python中称对象可以访问到的属性集合为属性空间-__dict__​属性

    • 对类和包可以直接访问,对函数而言其是空的