我试图理解python中浅拷贝和深拷贝之间的区别.我在这里阅读了很多帖子,他们一直很有帮助.但是,我仍然不太了解这种差异.有人可以解释下面结果的原因.评论中指出了我不理解的结果.
非常感谢.
import copy
import random
class understand_copy(object):
def __init__(self):
self.listofvalues = [4, 5]
def set_listofvalues(self, pos, value):
self.listofvalues[pos] = value
ins = understand_copy()
newins = copy.copy(ins)
newins.set_listofvalues(1,3)
print "ins = ", ins.listofvalues
print "in newins", newins.listofvalues
# Gives the following output as I would expect based on the explanations.
# prints ins = [4, 3]
# prints newins = [4, 3]
newins.listofvalues.append(5)
print "ins =", ins.listofvalues
print "newins =", newins.listofvalues
# Gives the following output as I would expect based on the explanations.
# prints ins = [4, 3, 5]
# prints newins = [4, 3, 5]
newins.listofvalues = [10, 11]
print "ins = ", ins.listofvalues
print "newins = ", newins.listofvalues
# Gives
# ins = [4, 3, 5]
# newins = [10, 11]
# This is the output that I do not understand.
# Why does ins.listofvalues not change this case.**
Run Code Online (Sandbox Code Playgroud)
在Python中,object的字段保持对对象的引用.因此,当您在示例中指定新列表时,您将更改该字段引用的对象,而不是其内容.在做作之前listofvalues
,两个对象的属性引用相同的列表,但在做作之后,它们引用了两个不同的列表.
这相当于以下代码:
>>> a = [4, 5]
>>> b = a
>>> b.append(3)
>>> b
[4, 5, 3]
>>> a
[4, 5, 3]
>>> b = [6, 7]
>>> b
[6, 7]
>>> a
[4, 5, 3]
Run Code Online (Sandbox Code Playgroud)
如果要更改列表的内容而不是参考,则需要使用切片.那是 :
>>> a = [4, 5, 3]
>>> b = a
>>> b[:] = [6, 7]
>>> b
[6, 7]
>>> a
[6, 7]
Run Code Online (Sandbox Code Playgroud)
注意:以下内容基于我对Python 2.6内部的理解.因此它实际上是特定于实现的,但是它给出的心理模型可能与语言规则的编写方式非常接近,并且应该适用于任何实现.
在Python中,始终通过引用访问对象(如在Java中,而不是在C++中).然而,变量名或属性名称可以是虽然在字典中作为结合,并且在CPython的被实现为这样的(除了局部变量的优化,的存在__slots__
,或通过暴露伪属性__getattr__
和朋友).
在Python中,每个对象作为私有字典将其每个属性名称映射到该值.并且解释器有两个私有字典,它将本地变量名和全局变量名之间的映射保存到它们的值.更改对象的变量或属性的值时,只需更改相应字典中的绑定即可.
因此,在您的示例中,您具有与以下代码中相同的行为:
def understand_copy():
return {'listofvalues': [4, 5]}
def deepcopy(obj):
if instance(obj, dict):
copy = {}
for key, value in obj.iteritems():
copy[key] = deepcopy(value) # Note the recursion
return copy
if instance(obj, list):
copy = []
for value in obj:
copy.append(deepcopy(value)) # Note the recursion
return copy
return obj
def copy(obj):
if instance(obj, dict):
copy = {}
for key, value in obj.iteritems():
copy[key] = value # No recursion this time, the copy is shallow
return copy
if instance(obj, list):
copy = []
for value in obj:
copy.append(value) # No recursion this time, the copy is shallow
return copy
return obj
globals = {}
globals['ins'] = understand_copy()
globals['new'] = copy(global['ins'])
# Now globals['ins']['listofvalues']
# and globals['new']['listofvalues']
# reference the same object!
globals['ins']['listofvalues'].__setitem__(0, 3)
globals['ins']['listofvalues'].append(5)
# We are calling function on one object,
# but not changing a binding, so the two
# 'listofvalues' attribute still refers
# to the same object.
globals['ins']['listofvalues'] = [10, 11]
# Now we changed the binding of the name
# in the dictionary 'ins' so now the two
# objects attributes points to different
# lists.
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3206 次 |
最近记录: |