Python是否在对象实例化时复制值或引用?

时间:2010-06-04 13:47:12

标签: python object language-design instantiation

也许是一个简单的问题,但我不能完全按照我的Google查询来查找答案。当我将对象传递给对象构造函数时,我习惯于复制对象,如下所示:

...
def __init__(self, name):
    self._name = name[:]
...

但是,当我运行以下测试代码时,似乎没有必要,Python在对象实例化时正在对对象值进行深层复制:

>>> class Candy(object):
...     def __init__(self, flavor):
...             self.flavor = flavor
...
>>> flav = "cherry"
>>> a = Candy(flav)
>>> a
<__main__.Candy object at 0x00CA4670>
>>> a.flavor
'cherry'
>>> flav += ' and grape'
>>> flav
'cherry and grape'
>>> a.flavor
'cherry'

那么,这里的真实故事是什么?谢谢!

修改

感谢@Olivier的出色回答。以下代码记录了Python通过引用进行复制的更好示例:

>>> flav = ['a','b']
>>> a = Candy(flav)
>>> a.flavor
['a', 'b']
>>> flav[1] = 'c'
>>> flav
['a', 'c']
>>> a.flavor
['a', 'c']

2 个答案:

答案 0 :(得分:13)

这是因为字符串不可变

如果对象是不可变的,那么运算符+=实际上重新分配它所应用的变量:

s = 'a'
ids = id(s)
s += 'b'
ids == id(s) # False, because s was reassigned to a new object

因此,在您的情况下,在开头,flava.flavor都指向相同的字符串对象:

flav --------\
               'cherry'
a.flavor ----/

但是当你写flav += 'and grape'时,变量flav会被重新分配到新的字符串对象:

flav --------> 'cherry and grape'
a.flavor ----> 'cherry' # <-- that string object never changes

这很令人困惑,因为通常,当您在变量上调用运算符时,它不会更改变量。但只是在不可变对象的情况下,它会重新分配变量。

所以对你的问题的最终答案是,是的,在实例化时复制对象是有意义的,特别是如果你期望一个可变对象(通常是这种情况)。对象是不可变的,无论如何复制它都不会有害。

答案 1 :(得分:1)

  

似乎没有必要

显示?您的问题完全关于设计和意义。这不是偏好或习惯问题。

类合同是否包含修改可变参数的能力?如果是这样,请不要复制。

类合同是否声明不会修改可变参数?如果是这样,你必须复制。

您的问题完全由通过合同定义解答