为什么方法无法访问类变量?

Tej*_*ade 4 python

我试图理解Python中的变量作用域,除了我不明白为什么类变量不能从其方法访问的部分之外,大多数事情对我来说都很清楚。
在以下示例中mydef1()无法访问a,但如果a在全局范围(类定义之外)中声明,则可以。

class MyClass1:
    a = 25
    def mydef1(self):
        print(a)
ins1 = MyClass1()
ins1.mydef1()
Run Code Online (Sandbox Code Playgroud)

输出

Traceback (most recent call last):
  File "E:\dev\Python\scope_test2.py", line 6, in <module>
    ins1.mydef1()
  File "E:\dev\Python\scope_test2.py", line 4, in mydef1
    print(a)
NameError: name 'a' is not defined
Run Code Online (Sandbox Code Playgroud)

dpw*_*pwr 7

重要的是要理解其中一些评论并不等同。MyClass.a是类本身的成员,self.a也是类实例的成员。

当你使用的时候self.a它会从类中返回,因为实例上a没有。a如果还有一个awhich是实例的成员,它将返回它。通常,实例 a 是使用__init__构造函数设置的。这两者可以同时存在。

class MyClass1:
    a = 25

    def __init__(self):
        self.a = 100

    def instance_a(self):
        print(self.a)

    def change_instance_a(self):
        self.a = 5

    def class_a(self):
        print(MyClass1.a)

    def change_class_a(self):
        MyClass1.a = 10


# Create two instances
ins1 = MyClass1()
ins2 = MyClass1()

# Both instances have the same Class member a, and the same instance member a
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()

# Now lets change instance a on one of our instances
ins1.change_instance_a()

# Print again, see that class a values remain the same, but instance a has
# changed on one instance only
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()

# Lets change the class member a on just one instance
ins1.change_class_a()

# Both instances now report that new value for the class member a
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
Run Code Online (Sandbox Code Playgroud)


gil*_*lch 6

简短的回答:这是 Python 的作用域规则。Python 中的嵌套函数具有词法作用域,但这不适用于嵌套在类中的内容。

class Foo:
    a = 25
    print(a)
    class Bar:
        print(a)
Run Code Online (Sandbox Code Playgroud)

第一个打印,但第二个是NameError.


更长的答案:

类级变量有一个函数闭包,但它全部包装__class__. (它的主要用途是在super()魔法中,这就是为什么它在 Python 3 中不再需要参数。)

class MyClass1:
    a = 25
    def mydef1(self):
        print(__class__.a)
ins1 = MyClass1()
ins1.mydef1()  # 25
Run Code Online (Sandbox Code Playgroud)

通常,您可以通过self参数访问这些内容以允许子类覆盖它们,但__class__甚至可以用于静态方法,它既没有self,也没有cls

class MyClass1:
    a = 25
    @staticmethod
    def mydef1():
        print(__class__.a)
ins1 = MyClass1()
ins1.mydef1()  # 25
Run Code Online (Sandbox Code Playgroud)

从技术上讲,类对象在类声明完成执行之前甚至不存在,这就是为什么你不能这样做

class Foo:
    a = 25
    class Bar:
        # NameError: free variable '__class__' referenced before assignment
        print(__class__.a)
Run Code Online (Sandbox Code Playgroud)

甚至,

class Foo:
    a = 25
    def bar():
        print(__class__.a)
    # NameError: free variable '__class__' referenced before assignment in enclosing scope
    bar()
Run Code Online (Sandbox Code Playgroud)

不过,您可以locals()在此之前访问该字典。

class Foo:
    a = 21
    locals()['a'] *= 2

Foo.a  # 42
Run Code Online (Sandbox Code Playgroud)

所以这有效。

class Foo:
    a = 25
    global foolocals
    foolocals = locals()
    def bar():
        print(foolocals['a'])
    bar()  # 25
Run Code Online (Sandbox Code Playgroud)