您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Python类作用域规则

Python类作用域规则

:此行为自Python 2.1 PEP 227:Nested Scopes以来就存在,并且在那时是已知的。如果名称是在类主体中分配的(例如y),则假定该名称是局部/全局变量;如果未将其分配给(x),则它也可能指向闭包单元。词汇变量不会显示为类主体的本地/全局名称

在Python 3.4上,dis.dis(func)显示以下内容

>>> dis.dis(func)
  4           0 LOAD_CONST               1 ('xlocal')
              3 STORE_DEREF              0 (x)

  5           6 LOAD_CONST               2 ('ylocal')
              9 STORE_FAST               0 (y)

  6          12 LOAD_BUILD_CLASS
             13 LOAD_CLOSURE             0 (x)
             16 BUILD_TUPLE              1
             19 LOAD_CONST               3 (<code object C at 0x7f083c9bbf60, file "test.py", line 6>)
             22 LOAD_CONST               4 ('C')
             25 MAKE_CLOSURE             0
             28 LOAD_CONST               4 ('C')
             31 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
             34 STORE_FAST               1 (C)
             37 LOAD_CONST               0 (None)
             40 RETURN_VALUE

LOAD_BUILD_CLASS负载加载builtins.__build_class__到堆栈上;这被称为参数__build_class__(func, name); 这里func是类的身体,name'C'。类主体是该函数的常量#3 func

>>> dis.dis(func.__code__.co_consts[3])
  6           0 LOAD_NAME                0 (__name__)
              3 STORE_NAME               1 (__module__)
              6 LOAD_CONST               0 ('func.<locals>.C')
              9 STORE_NAME               2 (__qualname__)

  7          12 LOAD_NAME                3 (print)
             15 LOAD_CLASSDEREF          0 (x)
             18 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             21 POP_TOP

  8          22 LOAD_NAME                3 (print)
             25 LOAD_NAME                4 (y)
             28 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             31 POP_TOP

  9          32 LOAD_CONST               1 (1)
             35 STORE_NAME               4 (y)
             38 LOAD_CONST               2 (None)
             41 RETURN_VALUE

在类体内,x通过LOAD_CLASSDEREF(15)访问,而y通过LOAD_NAME(25)加载。的LOAD_CLASSDEREF一个Python 3.4+操作码从具体内的类主体闭合细胞(在以前的版本,通用载荷值LOAD_DEREF被使用); 该LOAD_NAME是从装载值 当地人 ,然后全局 。但是,闭包单元既不显示为局部变量,也不显示全局变量

现在,由于该名称y存储在类主体中(35),因此该名称始终用作闭包单元而不是本地/全局名称。闭包单元格不会显示为类主体的局部变量。

自从实现PEP 227嵌套范围以来,这种行为就一直存在。当时BDFL声明不应解决此问题-因此,这已经超过13年了。

自PEP 227以来唯一的变化是nonlocal在Python 3中的添加;如果在类主体中使用它,则该类主体可以在包含范围内设置单元格的值:

x = "xtop"
y = "ytop"
def func():
    x = "xlocal"
    y = "ylocal"
    class C:
        nonlocal y  # y here Now refers to the outer variable
        print(x)
        print(y)
        y = 1

    print(y)
    print(C.y)

func()

现在的输出

xlocal
ylocal
1
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    func()
  File "test.py", line 13, in func
    print(C.y)
AttributeError: type object 'C' has no attribute 'y'

也就是说,print(y)读取y包含作用域的单元格y = 1的值,然后在该单元格中设置该值;在这种情况下,不会为class创建任何属性C

python 2022/1/1 18:27:14 有186人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶