当前位置: 首页 > 知识库问答 >
问题:

Python:定义类变量时哪些作用域是可访问的?

施永贞
2023-03-14

考虑这两个Python文件:

# file1.py
global_var = "abc"

class A:
    x = 1
    glb = global_var
    y = x + 1
    class B:
        z = 3
        glb = global_var
    zz = B.z

print(f"{A.B.z=}")
print(f"{A.zz=}")
# file2.py
global_var = "abc"

class A:
    x = 1
    glb = global_var
    y = x + 1
    class B:
        z = y + 1
        glb = global_var
    zz = B.z

print(f"{A.B.z=}")
print(f"{A.zz=}")

人们会期望他们做完全相同的事情。但他们没有!

$ python file1.py
A.B.z=3
A.zz=3
$ python file2.py
Traceback (most recent call last):
  File "file2.py", line 4, in <module>
    class A:
  File "file2.py", line 8, in A
    class B:
  File "file2.py", line 9, in B
    z = y + 1
NameError: name 'y' is not defined
  • 为什么B的定义可以访问全局范围,而不能访问A的范围?
  • 为什么y=x1应该工作,而z=y1不应该工作?这是一个设计决策,还是CPython未定义的行为?
  • 在计算类变量的值时,哪些变量/作用域可以访问的一般规则是什么?我什么时候应该考虑允许在定义类变量时使用哪个范围

共有2个答案

凌俊名
2023-03-14
  • 为什么B的定义可以访问全局范围,而不能访问A的范围

Chepner已经回答了这个问题,但简而言之:局部变量在全局命名空间中查找,因此类嵌套在代码示例中的方式符合预期。

  • 为什么y=x 1应该工作而z=y 1不应该工作?这是一个设计决策,还是CPython的未定义行为?

如上文所述,其工作正常。

  • 在计算类变量的值时,哪些变量/作用域可以访问的一般规则是什么?我什么时候应该考虑允许在定义类变量时使用哪个范围

它们不适用于具有LEGB规则/realpython的嵌套函数

定义类时,您正在创建一个新的本地Python作用域。在类的顶层指定的名称在此本地作用域中。在class语句中指定的名称与其他地方的名称不冲突。您可以说这些名称遵循LEGB规则,其中class块表示L层

在另一个类中嵌套一个类也不是很常见,通常你是这样做的类继承:

class B(A):
    y = A.y
    z =  y  + 1
    glb = global_var
养鸿运
2023-03-14

从…起https://docs.python.org/3/reference/executionmodel.html:

类定义块和exec()和ava()的参数在名称解析的上下文中是特殊的。类定义是可以使用和定义名称的可执行语句。这些引用遵循名称解析的正常规则,但在全局命名空间中查找未绑定的局部变量除外。类定义的命名空间成为类的属性字典。类块中定义的名称范围仅限于类块;它不扩展到方法的代码块——这包括理解和生成器表达式,因为它们是使用函数范围实现的。这意味着以下操作将失败:

B的定义中,y是一个未绑定的局部变量,因此在全局范围(未定义)中查找,而不是在包含的语句创建的命名空间中查找。

class语句根本没有定义作用域;它创建了一个命名空间,该命名空间被传递给元类,以便构造一个新类。

 类似资料:
  • 问题内容: 注意:这是在PHP中处理变量范围的参考问题。请关闭所有适合此模式的问题,以作为该问题的重复。 PHP中的“可变范围”是什么?一个.php文件中的变量可以在另一个文件中访问吗?为什么有时会出现 “未定义变量” 错误? 问题答案: 什么是“可变范围”? 变量具有有限的“作用域”或“可从其访问的位置”。仅仅因为你写一次 的地方 在你的应用程序并不意味着你可以参照从 到处 其他的应用程序中。该

  • 本文向大家介绍Python 如何访问外围作用域中的变量,包括了Python 如何访问外围作用域中的变量的使用技巧和注意事项,需要的朋友参考一下 在表达式中引用变量时,Python 会按照如下的顺序遍历各个作用域,寻找该变量: 当前函数作用域 任何外围作用域(比如包含当前函数的其他函数) global 作用域,即代码所在的模块的作用域 如果上述作用域内都找不到变量,就会报 NameError 异常。

  • 本文向大家介绍js的哪些操作可以改变作用域链?相关面试题,主要包含被问及js的哪些操作可以改变作用域链?时的应答技巧和注意事项,需要的朋友参考一下 比较有名的是的间接调用:

  • 问题内容: 如何从类定义中的列表理解中访问其他类变量?以下内容在Python 2中有效,但在Python 3中失败: Python 3.2给出了错误: 尝试Foo.x也不起作用。关于如何在Python 3中执行此操作的任何想法? 一个稍微复杂的激励示例: 在此示例中,apply()这是一个不错的解决方法,但可悲的是它已从Python 3中删除。 问题答案: 类范围和列表,集合或字典的理解以及生成器

  • 问题内容: 我注意到当在try {}中使用以下变量时,例如,从最后我不能在它们上使用方法: 但是,如果将声明放置在Try {}之前的main()中,则程序编译时没有错误,那么有人可以指出解决方案/答案/解决方法吗? 问题答案: 在进入块之前,需要声明变量,以使它们在方法的其余部分范围内:

  • 【闭包】和【作用域链】到底是谁让函数中的变量可以访问外层作用域中的变量?