我试图理解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)
重要的是要理解其中一些评论并不等同。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)
简短的回答:这是 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)