【问题标题】:Why does Python print this global variable instead of class attribute?为什么 Python 打印这个全局变量而不是类属性?
【发布时间】:2016-04-01 20:11:33
【问题描述】:

我试图了解 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__方法里面的print打印的是全局变量,而class body里面的print打印的是类属性x

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

【问题讨论】:

    标签: python


    【解决方案1】:

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

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

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

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

    你会得到一个关于x 变量的NameError,因为字典推导在它自己的范围内运行并且看不到在无范围类命名空间中定义的类变量x

    【讨论】:

    • 我喜欢dict理解不起作用的例子。
    【解决方案2】:

    导入模块

    每当您导入一个模块时,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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-25
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      相关资源
      最近更新 更多