19

基本的な質問は次のとおりa[i] += bです。

以下を考えると:

import numpy as np
a = np.arange(4)
i = a > 0
i
= array([False,  True,  True,  True], dtype=bool)

という事は承知しています:

  • a[i] = xa.__setitem__(i, x)で示される項目に直接割り当てると同じです。i
  • a += xは と同じでa.__iadd__(x)、その場で加算を行います

しかし、私が行うとどうなりますか:

a[i] += x

具体的には:

  1. これは と同じa[i] = a[i] + xですか? (これはインプレース操作ではありません)
  2. この場合、次の場合に違いがありますかi
    • intインデックス、または
    • ndarrayまたは
    • sliceオブジェクト_

バックグラウンド

私がこれを掘り下げ始めた理由は、重複したインデックスを操作するときに非直感的な動作に遭遇したためです。

a = np.zeros(4)
x = np.arange(4)
indices = np.zeros(4,dtype=np.int)  # duplicate indices
a[indices] += x
a
= array([ 3.,  0.,  0.,  0.])

この質問の重複インデックスに関するさらに興味深いもの。

4

4 に答える 4

17

最初に認識する必要があるのは、a += xが正確ににマップされるa.__iadd__(x)のではなく、 にマップされるということa = a.__iadd__(x)です。ドキュメントには、インプレース演算子が結果を返すと具体的に記載されていることに注意してください。これは必ずしもそうである必要はありませんself(ただし、実際には通常そうです)。これは、a[i] += x単純に次の場所にマップされることを意味します。

a.__setitem__(i, a.__getitem__(i).__iadd__(x))

したがって、追加は技術的にはインプレースで行われますが、一時オブジェクトでのみ行われます。ただし、を呼び出した場合よりも作成される一時オブジェクトが 1 つ少ない可能性があり__add__ます。

于 2013-04-16T10:59:41.287 に答える
2

Ivc が説明しているように、インプレースの項目追加メソッドはあり__getitem__ませ__iadd____setitem__。その動作を経験的に観察する方法は次のとおりです。

import numpy

class A(numpy.ndarray):
    def __getitem__(self, *args, **kwargs):
        print("getitem")
        return numpy.ndarray.__getitem__(self, *args, **kwargs)
    def __setitem__(self, *args, **kwargs):
        print("setitem")
        return numpy.ndarray.__setitem__(self, *args, **kwargs)
    def __iadd__(self, *args, **kwargs):
        print("iadd")
        return numpy.ndarray.__iadd__(self, *args, **kwargs)

a = A([1,2,3])
print("about to increment a[0]")
a[0] += 1

印刷します

about to increment a[0]
getitem
iadd
setitem
于 2013-04-16T11:10:51.843 に答える