2015-02-15 3 views
1

У меня есть этот питон кодРазница между й + = у и х = х + у

x = [1, 2, 3] 
y = x 
x += [4] 
>>> print(y) 
[1, 2, 3, 4] 

Таким образом, это происходит потому, что x is y является True и если я изменю x, меняю y

Но когда я делаю:

x = [1, 2, 3] 
y = x 
x = x + [4] 
>>> print(y) 
[1, 2, 3] 

и

>>> id(x) == id(y) 
False 

Интересно, в чем разница. Я думал, что x += 1 является сокращением для x = x+1, но, очевидно, должна быть разница.

Я была еще более запутанной, когда я попытался выше строк:

name = 'John' 
name_2 = name 
name += ' Doe' 

>>> print(name_2) 
'John' 

Так что я думаю, что эффект += зависит от объекта, на левой стороне, если она изменчива или нет?

+1

Да, ваше объяснение в последней строке вашего вопроса является правильным. (Ну, в основном, на самом деле это не зависит от того, является ли он изменчивым, но определяет ли он '__iadd__' фактическое мутирование объекта. Но в целом изменяемые типы будут делать это, если они разрешают операцию вообще.) – BrenBarn

+0

См. [In -place Operators] (https://docs.python.org/3/library/operator.html#inplace-operators). – user2864740

+0

@BrenBarn в порядке, и если я делаю 'x = x + 'foo'', он всегда будет создавать новый объект, потому что выражение справа является новым объектом? – Finn

ответ

1

Объект «слева» обрабатывает оператор (обычно, см. Формы r-оператора); в этом случае это Inplace Operator.

10.3.2. Операторы на месте

Многие операции имеют «на месте» версию. Ниже перечислены функции, обеспечивающие более примитивный доступ к операторам на месте, чем обычный синтаксис; например, утверждение x += y эквивалентно x = operator.iadd(x, y) ..

Фактический результат определяется «х» объекта и если он обрабатывает __iadd__ (например, мутируют, как со списками) или просто __add__ (например. новый объект результата, как и для строк) - выбор того, какой протокол использовать, и какое значение для возврата для назначения, определяется самим operator.iadd .

Так сокращенная из x += y ~~ x = x + y является только верно для некоторых объектов - в частности, те, которые являются статичными и [только] реализовать __add__.

См How are Python in-place operator functions different than the standard operator functions?


семантически operator.iadd функция работает примерно так:

if x.__iadd__: 
    x.__iadd__(y)  # side-effect performed on x, 
    return x    # returns original-but-modified object 
else 
    return x.__add__(y) # return new object, 
         # __add__ should not have side-effects 
0

как сказал @BrenBarn, если левая сторона объекта изменчиво будет преформ на месте. В противном случае будет возвращена новая копия, и поскольку она была скопирована, их идентификатор больше не будет соответствовать.

На заднем плане он идет что-то аналогичное этому:

>>> import copy 
>>> y = [1,2,3] 
>>> x = y 
>>> x+=[4] 
>>> y 
[1, 2, 3, 4] 
>>> x = copy.copy(y) #perhaps even a deepcopy()? Don't know. 
>>> y 
[1, 2, 3, 4] 
>>> x 
[1, 2, 3, 4] 
>>> x += [5] 
>>> y 
[1, 2, 3, 4] 
>>> x 
[1, 2, 3, 4, 5] 

EDIT 1:

class test(): 
    def __init__(self, ll): 
     self.a = ll 
    def __add__(self, other): 
     return test(ll=self.a+other.a) 

>>> a = test([[1,2],[3,4]]) 
>>> a.a 
[[1, 2], [3, 4]] 
>>> x = test([[1,2],[3,4]]) 
>>> x += a 
>>> x.a 
[[1, 2], [3, 4], [1, 2], [3, 4]] 
>>> a.a 
[[1, 2], [3, 4]] 
>>> x.a[2][0] = 7 
>>> x.a 
[[1, 2], [3, 4], [7, 2], [3, 4]] 
>>> a.a 
[[7, 2], [3, 4]] 
+1

'x = y [:] или x = y.copy() 'все, что необходимо, вам не нужно импортировать копию –

+0

@PadraicCunningham thnx. На самом деле не знал, что ... Как насчет копии и глубокой копии? Я полагаю, что если это родной тип, это jsut копировать экземпляр класса, который вы сделали, вероятно, за счет deepcopy? Хотя я не понимаю, как они отслеживают разницу. – ljetibo

+0

, если вы храните другие объекты в списке, тогда вы будете использовать deepcopy, поскольку [:] или list.copy выполняют только мелкую копию. –

Смежные вопросы