Копирует ли значение Python или ссылку на экземпляр объекта?
Простой вопрос, возможно, но я не могу полностью рассказать о своем запросе 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'
Итак, что это за настоящая история? Спасибо!
EDIT:
Спасибо @Olivier за его отличный ответ. Следующий код документирует лучший пример, который Python копирует по ссылке:
>>> flav = ['a','b']
>>> a = Candy(flav)
>>> a.flavor
['a', 'b']
>>> flav[1] = 'c'
>>> flav
['a', 'c']
>>> a.flavor
['a', 'c']
Ответы
Ответ 1
Это потому, что строки неизменяемы.
Оператор +=
, скорее путающе, фактически переназначает переменную, к которой она применяется, если объект неизменен:
s = 'a'
ids = id(s)
s += 'b'
ids == id(s) # False, because s was reassigned to a new object
Итак, в вашем случае в начале оба flav
и a.flavor
указывают на один и тот же строковый объект:
flav --------\
'cherry'
a.flavor ----/
Но когда вы пишете flav += 'and grape'
, переменная flav
получает переназначенный для нового строкового объекта:
flav --------> 'cherry and grape'
a.flavor ----> 'cherry' # <-- that string object never changes
Это сбивает с толку, потому что обычно, когда вы вызываете оператор на переменную, он не меняет эту переменную. Но как раз в случае неизменяемого объекта, он переназначает переменную.
Итак, окончательный ответ на ваш вопрос: да, имеет смысл копировать объекты при создании экземпляра, особенно если вы ожидаете изменчивый объект (что часто бывает). Это объект был неизменным, он не повредит, чтобы его скопировать.
Ответ 2
кажется, что это необязательно
Появляется? Ваш вопрос полностью о дизайне и значении. Это не вопрос предпочтения или привычки.
Включает ли контракт класса возможность модифицировать изменяемый аргумент? Если это так, НЕ делайте копию.
Утверждается ли контракт класса, что изменяемый аргумент не будет изменен? Если это так, вы ДОЛЖНЫ сделать копию.
На ваши вопросы полностью отвечает определение контракта для класса.