类中的python列表范围
我遇到了一些与此代码有关的意外行为:类中的python列表范围,python,python-3.x,Python,Python 3.x,我遇到了一些与此代码有关的意外行为: 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
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)
我收到输出:
['1', '2', '3']
['1', '2', '3']
['1', '2', '3']
'nothing'
但我希望得到:
['1']
['1', '2']
['1', '3']
'nothing'
我不明白的是:
class b (a):
x = a.x
为a.x
创建另一个“名称”,即x
(在该范围内),但它们是相同的对象。如果您附加到x
,您也将附加到a.x
——它将附加到同一个对象
你唯一能做不同事情的地方就是
x = 'nothing'
现在将x
绑定到另一个对象,即字符串
如果您将代码更改为
class b (a):
x = a.x.copy()
您将得到不同的行为:这意味着x
现在是列表副本的“名称”,即a.x
您的行
class b (a):
x = a.x
为a.x
创建另一个“名称”,即x
(在该范围内),但它们是相同的对象。如果您附加到x
,您也将附加到a.x
——它将附加到同一个对象
你唯一能做不同事情的地方就是
x = 'nothing'
现在将x
绑定到另一个对象,即字符串
如果您将代码更改为
class b (a):
x = a.x.copy()
您将得到不同的行为:这意味着
x
现在是列表副本的“名称”,即a.x
1。2.在执行x=a.x
操作时,您只是将x
赋值为指向唯一现有的列表,即a
中的列表,因此在x
上操作时,这会反映在a.x
上,因为这是相同的列表,而不是副本。这对于b类
和c类
都是正确的。复印
x = list(a.x)
3.当执行
x='nothing'
时,您将一个字符串分配到x
中,该字符串不再指向列表,只指向列表。2.在执行x=a.x
操作时,您只是将x
赋值为指向唯一现有的列表,即a
中的列表,因此在x
上操作时,这会反映在a.x
上,因为这是相同的列表,而不是副本。这对于b类
和c类
都是正确的。复印
x = list(a.x)
3.在执行
x='nothing'
时,您将字符串分配到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中,一切都是对象,而变量只是对象的绑定
因此x=[1]
创建对象[1]
,并将x
变量绑定到该对象
然后执行y=x
操作时,不会创建新对象,它只是将y
绑定到现有对象。这意味着x
和y
现在都绑定到同一个对象,因此,当您执行修改对象的操作时,例如x.append()
,将同时影响x
和y
这不会发生在z=x时;z='nothing'
因为第二步是创建一个新对象并将z
绑定到它,这样x/y
和z
现在就绑定到不同的对象
以下两种情况都不会发生这种情况:
z = x[:]
z = [item for item in x]
因为这两个对象也会创建一个新对象(原始对象(1)的副本),将x
和z
分开
通过检查每个变量的id(可能是您应该使用id
的唯一原因)可以看到效果,为了可读性,删除了公共前缀:
>>> print(id(x)); print(id(y)); print(id(z))
49864
49864
53808
您可以看到x
和y
是相同的对象,而z
则不同
(1) 请记住,如果您的数据结构足够复杂,您可能需要进行深度复制,例如(添加注释):
对于新的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中,一切都是对象,而变量只是对象的绑定
因此x=[1]
创建对象[1]
,并将x
变量绑定到该对象
然后执行y=x
操作时,不会创建新对象,它只是将y
绑定到现有对象。这意味着x
和y
现在都绑定到同一个对象,因此,当您执行修改对象的操作时,例如x.append()
,将同时影响x
和y
这不会发生在z=x时;z='nothing'
因为第二步是创建一个新对象并将z
绑定到它,这样x/y
和z
现在就绑定到不同的对象
以下两种情况都不会发生这种情况:
z = x[:]
z = [item for item in x]
因为这两个对象也会创建一个新对象(原始对象(1)的副本),将x
和z
分开
通过检查每个变量的id(可能是您应该使用id
的唯一原因)可以看到效果,为了可读性,删除了公共前缀:
>>> print(id(x)); print(id(y)); print(id(z))
49864
49864
53808
您可以看到x
和y
是相同的对象,而z
则不同
(1) 请记住,如果您的数据结构足够复杂,您可能需要进行深度复制,例如(添加注释):
当你这样定义它的时候。用父类和每个chil初始化变量x