为什么Python打印这个全局变量而不是类属性?

时间:2015-12-27 22:52:02

标签: python

我试图了解Python代码何时引用模块级变量与类级变量。我在模块main.py'

中有以下代码
## main.py

# global variable x
x = "I am global and I love it!"

class SomeClass:
    x = "I am a class attribute, and life is good!"
    print(x)  # prints "I am a class attribute, and life is good!"
    def __init__(self):
        print(x)  # prints "I am global and I love it!"  Why?

print(x)  # prints "I am global and I love it!"
SomeClass()

导入此模块时,输出为:

I am a class attribute, and life is good!
I am global and I love it!
I am global and I love it!

为什么SomeClass.__init__方法中的打印打印全局变量,而类主体内的打印打印类属性x

这是从Python邮件列表上的一个问题中解释的:https://mail.python.org/pipermail/python-list/2015-December/701167.html

2 个答案:

答案 0 :(得分:5)

Python中的类定义创建了一个名称空间,但它们并没有创建新的作用域。这意味着在类中定义的函数不能直接访问包含类的变量。相反,他们必须将它们作为类或实例的属性进行访问。

因此,您可以使用x__init__来获取类变量,而不是访问示例SomeClass.x函数中的self.x

print(x)在类体中起作用的原因是该代码以类名称空间作为其本地名称空间运行。如果您尝试在类级别执行更复杂的操作,可能会遇到许多问题,因为无范围命名空间是一个相当奇怪的环境。例如,这不起作用:

class Foo:
    x = 1
    dct = {i: x for i in range(10)}

您将获得NameError关于x变量的x因为字典理解在其自己的范围内运行,并且无法看到在无范围内定义的类变量$output = shell_exec($command); echo ($output); class namespace。

答案 1 :(得分:1)

导入模块

每当导入模块时,Python都会按照编写模块的顺序执行所有模块级代码。它将所有已定义的名称附加到模块对象,模块的导入程序可以通过模块对象访问所有已定义的名称。这样您就可以导入模块,模块中的名称不会破坏您的命名空间。

import main  # executes the script main.py, then creates a module
print(main.x)

定义一个类

你可以想象Python创建类的方式与创建模块的方式类似:执行类主体中的所有代码,然后将定义的名称分配给类__init__方法也成为了类的属性; 到调用函数时,类已构造,在函数中,您只能将x类属性称为SomeClass.x(或self.x__init__)内。类定义的名称空间与模块的名称空间不同,因此类中的print(x)首先找到类名称空间,因为print位于同一名称空间中。

除了

正如您在进入时无法引用当前模块一样,您也无法参考当前的课程。例如:

class SomeOtherClass:
    x = 5
    SomeOtherClass.x = 6  # This fails!

您无法引用该类的原因与您无法在模块中引用您所在的模块相同:名称尚未创建。

这个答案的灵感来自ChrisA's answer on the Python mailing list