在学习了列表、方框图和指针图之后,我决定为自己创建一些随机的东西,并测试一下我的知识。我将使用“浅拷贝”和“疑似浅拷贝”这两个词,因为我不太确定它们的定义是否正确。我的疑问是在为这些代码的行为提供原因时,请告诉我我是否思考正确。在
代码A
from copy import *
x=[1,[2,[3,[4]]]] #normal copy/hardcopy
a=x
v=list(x) #suspected shallow copy
y=x.copy() #shallow copy
z=deepcopy(x) #theoretical deep copy
w=x[:] #suspected shallow copy
def test():
print("Original:",x)
print("hardcopy:",a)
print("suspected shallow copy",v)
print("shallow copy",y)
print("deep copy:",z)
print("suspected shallow copy",w)
x[1]=x[1]+[4]
test()
输出A:
^{pr2}$代码B
^{3}$输出B: 我在这里看到了IDLE中的TypeError,但是list元素的变异仍然完成了,并且跨越了a、b、c
从输出B继续:
a[2][0]=a[2][0]+99
a,b,c
输出C:
((1, 2, [100, 2, 3, 3]), (1, 2, [100, 2, 3, 3]), (1, 2, [100, 2, 3, 3]))
代码D:
a=[1,2,(1,2,3)]
def shallow_copy(x):
tup=[]
for i in x:
tup+=[i]
return tup
def hardcopy(x):
return x
b=hardcopy(a)
c=shallow_copy(a)
d=a.copy()
a[2]=a[2]+(4,)
a,b,c,d
输出D:
[1, 2, (1, 2, 3, 4)], [1, 2, (1, 2, 3, 4)],
[1, 2, (1, 2, 3)], [1, 2, (1, 2, 3)]
From Output A, we observe the following: 1)For lists which have shallow copies, doing
x[1]=x[1]+[4]
does not affect the shallow copies. My reasons for the above could bea)
=
followed by+
does__add__
instead of__iadd__
(which is+=
), and doing__add__
should not modify the object, only changing the value for one pointer(x and its hardcopy in this case)
这在输出B中得到了进一步的支持,但在输出C中却有点矛盾,这可能部分是由于下面的原因(B),但不能太肯定。在
b) We executed this in the first layer(only 1 slice operator), maybe there's some kind of rule which prevents these elements from being modified.
输出B和输出C都支持这一点,尽管输出B可能被认为位于第一层,但可以将其视为增加第二层中的元素,它符合上述观察结果。在
2)What is the reason why the TypeError appeared in Output B, but is still executed? I know that whether an Exception might be triggered is based on the final sequence you are actually changing(the list in this case), but why is there still
TypeError: 'tuple' object does not support item assignment
?
我对上述问题提出了自己的看法。我很欣赏关于这个问题的任何想法(最好是理论上的解决方案),因为我对编程还是比较陌生的。在
回答问题1,这个问题看起来很复杂,但答案可能很简单:
当您有另一个名称引用原始对象时,您将看到原始对象中的更改。如果(!)您可以使用
x[1] = x[1] + [4]
的形式更改对象。这是因为您将一个新对象分配给x[1]
,而不是像x[1].append(4)
中那样进行就地更改。在您可以使用
id()
函数检查它。在回答您的问题2,并改编自官方文件:
让我们做
那么
^{pr2}$这和
iadd
改变了列表的位置,但是分配失败了,因为您不能分配给元组(不可变类型)索引。在如果你
连接进入一个新的list对象,然后对元组索引的赋值也会失败。但是新的物体丢失了。
a[0]
未进行适当更改。在为了澄清OP的评论,直接从here中的文档中可以看出
至于你的输出D: 写作
除了写作什么都不做
实际上,
b
是一个新名称,它引用了a
引用的同一对象。 这是因为a
是可变的,因此指向原始对象的引用被传递到本地函数名x
。返回x
只是将相同的引用返回到b
。在这就是为什么您看到}引用一个新的元组}和{}仍然引用旧的tuple对象。现在因为它们是元组,所以你不能像列表一样在适当的地方改变它们。在
a
中进一步的变化反映在b
中。再次通过赋值使a[2]
成为一个新的不同的对象元组,所以现在a[2]
和{(1,2,3,4)
,而{至于“硬拷贝”这个词,我不会用的。它在官方文档中甚至没有出现过一次,在Python中提到的这个问题旁边的问题也会出现在其他上下文中。它是模棱两可的(与“浅”和“深”相反,这两个词很好地说明了它们的含义)。我认为与你描述的术语“硬拷贝”完全相反(一个对象副本)(指向同一对象的附加名称/引用/指针)。当然,最终有很多方法可以表达同样的观点。我们说“copy”是因为它比较短,而对于不可变的,复制是否发生并不重要(无论如何,您不能更改它们)。对于可变表来说,“copy”通常意味着“shallow copy”,因为如果您想要“deep copy”,您必须在代码中“更进一步”。在
相关问题 更多 >
编程相关推荐