为什么 class 方法中的这个实例变量赋值不会导致 Python 中的 UnboundLocalError
why this instance variable assignment in class method not cause UnboundLocalError in Python
在下面的代码中,如果在函数 foo 中对名称 v 使用赋值语句,解释器将给出 unboundlocalerror,因为这会在函数范围内创建一个同名变量,我们尝试在局部赋值之前引用它。但是为什么在实例方法中对实例变量做同样的事情不会给出任何错误? Python 评估 self.v = self.v + 1
和 v = v + 1
时有什么区别?
class A:
v = 1
def foo(self):
self.v = self.v + 1
v = 1
def foo():
v = v + 1
# UnboundLocalError: local variable 'v' referenced before assignment
foo()
a = A()
# print 1
print(a.v)
a.foo()
# print 1 2
print(a.__class__.v, a.v)
局部变量解析是静态的。在字节码编译时,Python 识别出 foo
有一个 v
局部变量,因此在 foo
中对 v
的所有访问都转到局部变量,即使局部变量未绑定。
实例属性解析是动态的。每当执行 self.v
访问时,Python 会搜索继承层次结构中的实例字典和 class 字典,以确定 v
应该是什么。 (不过,除非定义了其他一些自定义行为,否则赋值总是转到实例字典。)
与局部变量不同,对 self.v
的赋值本身并不影响属性访问解析的内容,并且 self.v
的重复访问可能解析不同;一次访问可能在实例字典中找不到任何内容,并解析为 class 字典中的 'v'
条目,而稍后的条目可能会发现此时实例字典中存在 'v'
条目,并解决这个问题。
在下面的代码中,如果在函数 foo 中对名称 v 使用赋值语句,解释器将给出 unboundlocalerror,因为这会在函数范围内创建一个同名变量,我们尝试在局部赋值之前引用它。但是为什么在实例方法中对实例变量做同样的事情不会给出任何错误? Python 评估 self.v = self.v + 1
和 v = v + 1
时有什么区别?
class A:
v = 1
def foo(self):
self.v = self.v + 1
v = 1
def foo():
v = v + 1
# UnboundLocalError: local variable 'v' referenced before assignment
foo()
a = A()
# print 1
print(a.v)
a.foo()
# print 1 2
print(a.__class__.v, a.v)
局部变量解析是静态的。在字节码编译时,Python 识别出 foo
有一个 v
局部变量,因此在 foo
中对 v
的所有访问都转到局部变量,即使局部变量未绑定。
实例属性解析是动态的。每当执行 self.v
访问时,Python 会搜索继承层次结构中的实例字典和 class 字典,以确定 v
应该是什么。 (不过,除非定义了其他一些自定义行为,否则赋值总是转到实例字典。)
与局部变量不同,对 self.v
的赋值本身并不影响属性访问解析的内容,并且 self.v
的重复访问可能解析不同;一次访问可能在实例字典中找不到任何内容,并解析为 class 字典中的 'v'
条目,而稍后的条目可能会发现此时实例字典中存在 'v'
条目,并解决这个问题。