[英]python list scope in class
我遇到了这段代码的一些意外行为:
from pprint import pprint
class a (object):
x = ['1']
class b (a):
x = a.x
x.append('2')
class c (a):
x = a.x
x.append('3')
class d (a):
x = a.x
x = 'nothing'
if __name__ == '__main__':
pprint(a.x)
pprint(b.x)
pprint(c.x)
pprint(d.x)
我收到 output:
['1', '2', '3']
['1', '2', '3']
['1', '2', '3']
'nothing'
但我希望收到:
['1']
['1', '2']
['1', '3']
'nothing'
我不明白的是:
你的线
class b (a):
x = a.x
为ax
创建另一个“名称”,即x
(在该范围内),但它们是相同的 object。 如果您将 append 附加到x
,您还附加到ax
- 它附加到相同的 object。
你做一些不同的事情的唯一地方是在
x = 'nothing'
您现在将x
绑定到不同的 object,一个字符串。
如果您将代码更改为
class b (a):
x = a.x.copy()
你会得到不同的行为:这表示x
现在是ax
列表副本的“名称”。
1. 2.在执行x = ax
时,您只是将x
指向唯一存在的列表,即来自a
的列表,因此在对x
进行操作时,这反映在ax
上,因为这是同一个列表,而不是副本。 这对于class b
和class c
都是正确的。 做一个副本
x = list(a.x)
3.执行x='nothing'
时,您将一个字符串分配给x
,该字符串不再指向列表,仅此而已
当您以这种方式定义它时。 变量 x 使用父 class 初始化,每个继承 class 的子都引用该变量(不是副本)。 它成为 class 名称下的全局变量。
要实现您期望的 output:
from pprint import pprint
class a (object):
def __init__(self):
self.x = ['1']
class b (a):
def __init__(self):
super().__init__()
self.x.append('2')
class c (a):
def __init__(self):
super().__init__()
self.x.append('3')
class d (a):
def __init__(self):
super().__init__()
self.x = 'nothing'
if __name__ == '__main__':
pprint(a().x)
pprint(b().x)
pprint(c().x)
pprint(d().x)
对于新的 Python 开发人员来说,这可能是最难理解的事情之一,当他们最终理解时,这将成为一个真正的顿悟。 您所拥有的与以下内容没有什么不同:
>>> x = [1]; print(x)
[1]
>>> y = x; print(x); print(y)
[1]
[1]
>>> y.append(2); print(x); print(y)
[1, 2]
[1, 2]
>>> z = x; z = 'nothing'; print(x); print(y); print(z)
[1, 2]
[1, 2]
nothing
这样做的原因是因为在 Python 中,一切都是 object 并且变量只是与对象的绑定。
所以x = [1]
创建了object [1]
并将x
变量绑定到它。
然后,当您执行y = x
时,不会创建新的 object,它只是将y
绑定到已经存在的 object。 这意味着x
和y
现在都绑定到同一个object 因此,当您执行修改 object 的操作时,例如x.append()
, x
和y
都会受到影响。
z = x; z = 'nothing'
不会发生这种情况。 z = x; z = 'nothing'
因为第二步是创建一个新的 object 并将z
绑定到它,因此x/y
和z
现在绑定到不同的东西。
它也不会发生在以下任何一种情况下:
z = x[:]
z = [item for item in x]
因为这两个还创建了一个新的 object (原始(1)的副本),将x
和z
分开。
通过检查每个变量的 ID(可能是您应该使用id
的唯一原因)可以看到效果,为了便于阅读,删除了公共前缀:
>>> print(id(x)); print(id(y)); print(id(z))
49864
49864
53808
可以看到x
和y
是同一个object, z
是不同的。
(1)请记住,如果您的数据结构足够复杂,您可能需要进行深拷贝,例如(添加注释):
>>> x = [[1,2],[3,4]]; y = x; print(id(x)); print(id(y))
773190920 # same object
773190920
>>> y = x[:]; print(id(x)); print(id(y))
773190920 # different objects
832649864
>>> print(id(x[0])); print(id(y[0]))
773088840 # but the sub-objects are still identical.
773088840
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.