2010-08-10 36 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__

這些方法稱爲實現增強算術任務(+ =, - =,* =,/ =,// =,(%)=,** =,< < =,> > =,& =,^ =,| =)。 這些方法應嘗試就地操作(修改自我)並返回結果(可能是,但不一定是自己)。

當然是可以實現__add____iadd__有一些其他的行爲,如果你想,但你看到什麼是標準和推薦的方式。而且,是的,你第一次看到它有點令人驚訝。

+0

是這種差異特定於蟒或者是它的'+'與'+ ='在編程語言運營商的共同特徵? – 2010-08-10 09:52:58

+0

@bgbg:這是針對Python的。在C#中,例如'a = a + b'幾乎等同於'a + = b'。 – 2010-08-10 10:05:39

+0

如果您認爲+ =作爲遞增操作而不是快捷方式來添加值,則可以提供幫助。 – 2010-08-10 10:22:49

7

你沒看錯,有時真的a += ba = 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] 

。當然,這同樣適用於所有其他就地運營商,-=*=//=%=