2010-08-10 3 views
8

Рассмотрите следующий сеанс. Как объясняются различия? Я думал, что a += b является синтаксическим сахаром (и, следовательно, эквивалентным) a = a + b. Очевидно, я ошибаюсь.Обработка данных по ссылке или по значению в python

>>> 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.]] 

Спасибо

ответ

15

Использование + результатов оператора при вызове метода специальных __add__, который должен создать новый объект и не должны изменять оригинал.

С другой стороны, использование оператора += приводит к вызову __iadd__, который должен по возможности модифицировать объект, а не создавать новый объект.

__add__

Эти методы вызываются для выполнения бинарных арифметических операций (+, -, *, //,%, divmod(), Pow(), **, < <,> >, &, ^, |). Например, чтобы оценить выражение x + y, где x является экземпляром класса, который имеет метод __add __(), вызывается x .__ add __ (y).

__iadd__

Этих методы призваны выполнять дополненные арифметические задания (+ =, - =, * =,/= // =,% = ** =, < < =,> > =, & =,^=, | =). Эти методы должны попытаться выполнить операцию на месте (изменение self) и вернуть результат (который может быть, но не обязательно, сам).

Конечно, можно реализовать __add__ и __iadd__ иметь некоторое другое поведение, если вы хотите, но то, что вы наблюдаете это стандартный и рекомендуемый способ. И, да, в первый раз, когда вы это видите, это немного удивительно.

+0

эта разница специфичны для питона или это общая черта '+' 'против + =' операторов в языках программирования? –

+0

@bgbg: Это относится к Python. В C#, например, 'a = a + b' почти эквивалентно' a + = b'. –

+0

Помогает, если вы считаете + = как операцию приращения, а не сокращенную для добавления значений. –

7

Вы не ошибаетесь, иногда a += b действительно является синтаксически a = a + b, но иногда это не так, что один из наиболее запутанных особенностей Python - см this similar question для более подробного обсуждения.

+ оператор вызывает специальный метод __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] 

Конечно то же самое для всех остальных на месте операторы, -=, *=, //=, %= и т.д.

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