numpy.arrayインプレース演算の落とし穴(Python)
概要
Python numpyでインプレース演算(+=
など)をした際に思わぬ挙動をすることがあるので、
その確認をする。
内容
環境
macOS Catalina
Python 3.7.0
numpy 1.18.3
再現
>>> import numpy as np
>>> a = np.array([3])
>>> b, c = a, a
>>> a, b, c
(array([3]), array([3]), array([3]))
>>> c += 1
>>> a, b, c
(array([4]), array([4]), array([4]))
分析
a
, b
, c
が参照しているのは、np.array
オブジェクトに対してであるが、
+=1
が実は変更したのは、その属性であるからである。
下記のように、+=1
がオブジェクト自体を変更する場合は、予想通りの変化になる。
>>> a = 3
>>> b, c = a, a
>>> a, b, c
(3, 3, 3)
>>> c += 1
>>> a, b, c
(3, 3, 4)
>>>
解決策
c = c + 1
とし、オブジェクトを新たに生成する。
>>> import numpy as np
>>> a = np.array([3])
>>> b, c = a, a
>>> c = c + 1
>>> a, b, c
(array([3]), array([3]), array([4]))
蛇足
id
関数を使って確認することもできる。
>>> import numpy as np
>>> a = np.array([3])
>>> b, c = a, a
>>> id(a), id(b), id(c)
(4692042016, 4692042016, 4692042016)
>>> c += 1
>>> a, b, c
(array([4]), array([4]), array([4]))
>>> id(a), id(b), id(c)
(4692042016, 4692042016, 4692042016)
>>> c = c + 1
>>> a, b, c
(array([4]), array([4]), array([5]))
>>> id(a), id(b), id(c)
(4692042016, 4692042016, 4692041936)
なお、属性の直接の変更は、下記のように同一オブジェクトを参照している場合は、どちらも変わって見える。
インプレースかどうかの問題ではなく、オブジェクトと参照の問題であるはず。(言葉足らず)
>>> class Obj: pass
...
>>> a = Obj()
>>> a.name = 'mori'
>>> b = a
>>> a.name, b.name
('mori', 'mori')
>>> a.name += 'ta'
>>> a.name, b.name
('morita', 'morita')
>>> a.name = a.name + 'rou'
>>> a.name, b.name
('moritarou', 'moritarou')
参考にさせていただいた本
『ゼロから作るDeep Learning③ フレームワーク編』斎藤康毅著 O'REILLY
感想
numpyの配列を使う際に、気を付けようと思った。
今後
代入演算子に注意。
Author And Source
この問題について(numpy.arrayインプレース演算の落とし穴(Python)), 我々は、より多くの情報をここで見つけました https://qiita.com/yo314159265/items/500001bf5481931e42fa著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .