Рассмотрите следующую сессию. Как различия объяснены? Я думал это a += b
синтаксический сахар (и таким образом эквивалентный) a = a + b
. Очевидно, я неправ.
>>> import numpy as np
>>> a = np.arange(24.).reshape(4,6)
>>> print a
[[ 0. 1. 2. 3. 4. 5.]
[ 6. 7. 8. 9. 10. 11.]
[ 12. 13. 14. 15. 16. 17.]
[ 18. 19. 20. 21. 22. 23.]]
>>> for line in a:
... line += 100
...
>>> print a #a has been changed
[[ 100. 101. 102. 103. 104. 105.]
[ 106. 107. 108. 109. 110. 111.]
[ 112. 113. 114. 115. 116. 117.]
[ 118. 119. 120. 121. 122. 123.]]
>>>
>>> for line in a:
... line = line + 999
...
>>> print a #a hasn't been changed
[[ 100. 101. 102. 103. 104. 105.]
[ 106. 107. 108. 109. 110. 111.]
[ 112. 113. 114. 115. 116. 117.]
[ 118. 119. 120. 121. 122. 123.]]
Спасибо
Использование оператора +
приводит к вызову специального метода __ add __
, который должен создать новый объект и не должен изменять оригинал.
С другой стороны, использование оператора + =
приводит к вызову __ iadd __
, который должен изменить объект, если это возможно, а не создавать новый объект.
__ add __
Эти методы вызываются для реализации бинарных арифметических операций (+, -, *, //,%, divmod (), pow (), **, <<, >>, &, ^, |). Например, чтобы оценить выражение x + y, где x - это экземпляр класса, имеющего метод __add __ (), вызывается x .__ add __ (y).
__ iadd __
Эти методы вызываются для реализации расширенных арифметических присваиваний (+ =, - =, * =, / =, // =,% =, ** =, << =, >> =, & =, ^ =, | =). Эти методы должны попытаться выполнить операцию на месте (изменить себя) и вернуть результат (который может быть, но не обязательно, самим собой).
Конечно, можно реализовать __ add __
и __ iadd __
, чтобы иметь другое поведение, если хотите, но то, что вы наблюдаете, является стандартным и рекомендуемым способом. И, да, это немного удивительно, когда видишь это впервые.
Вы не ошиблись, иногда a + = b
действительно является синтаксическим сахаром для a = a + b
, но иногда это не так, что является одной из наиболее сбивающих с толку функций Python - см. этот аналогичный вопрос для более подробного обсуждения.
Оператор +
вызывает специальный метод __ add __
, а оператор + =
пытается вызвать на месте ] __ iadd __
специальный метод, но я думаю, что стоит расширить случай, когда __ iadd __
не определен.
Если оператор на месте не определен, например для неизменяемых типов, таких как строки и целые числа, вместо этого вызывается __ add __
. Итак, для этих типов a + = b
на самом деле является синтаксическим сахаром для a = a + b
. Этот игрушечный класс иллюстрирует эту мысль:
>>> class A(object):
... def __add__(self, other):
... print "In __add__ (not __iadd__)"
... return A()
...
>>> a = A()
>>> a = a + 1
In __add__ (not __iadd__)
>>> a += 1
In __add__ (not __iadd__)
Это поведение, которое вы должны ожидать от любого неизменяемого типа.Хотя это может сбивать с толку, альтернативой было бы запретить + =
для неизменяемых типов, что было бы неудачно, поскольку это означало бы, что вы не могли бы использовать его для строк или целых чисел!
В другом примере это приводит к различию между списками и кортежами, оба из которых поддерживают + =
, но могут быть изменены только списки:
>>> a = (1, 2)
>>> b = a
>>> b += (3, 4) # b = b + (3, 4) (creates new tuple, doesn't modify)
>>> a
(1, 2)
>>> a = [1, 2]
>>> b = a
>>> b += [3, 4] # calls __iadd___ so modifies b (and so a also)
>>> a
[1, 2, 3, 4]
Конечно, то же самое касается всех остальных в операторы -place, - =
, * =
, // =
, % =
и т. д.