17871


PythonとNumpyの以下のプログラムに関する質問です。

[code]

    import numpy as np
    
    total = np.array([0,0,0])
    
    total_list = []
    
    array_list = [np.array([0,0,0]), np.array([1,2,3]), np.array([4,5,6])]
    
    for array in array_list:
    
        total += array
    
        total_list.append(total)
    
    print total_list
    
[/code]

単純に、array_listの要素を前から足し込んだものを、  
total_listにappendするだけです。

本来ならば、  
[array([0, 0, 0]), array([1, 2, 3]), array([5, 7, 9])]  
という出力になると思うのですが、  
[array([5, 7, 9]), array([5, 7, 9]), array([5, 7, 9])]  
と出力されてしまいます。

すごく初歩的なのかもしれませんが、このバグが取れません。  
申し訳ありませんが、よろしくお願いします。


CC BY-SA 3.0
2015-10-20T18:41:46.590
17870
2015-11-20T16:48:13.007
2015-11-20T16:48:13.007
10685
12874
question
python
Pythonでforループを使ってリストを生成すると、すべての要素が同じ値になる


基本的に Python では、変数は参照型です。つまりオブジェクト (値) の実体は、変数とは別の場所にあって、変数はその場所を指しているだけです。

提示されたコードでは、ループの一回目が終わった時は、こんな感じになっています。

[code]

    total --------> [0,0,0]
                     ^
    list             |
    [0] -------------+
    
[/code]

二回目のループで `total += array` を行った時に、実体を直接アップデートするので、こうなります。

[code]

    total --------> [1,2,3]
                     ^
    list             |
    [0] -------------+
    
[/code]

その直後の append では同じ参照を追加するので

[code]

    total --------> [1,2,3]
                     ^ ^
    list             | |
    [0] -------------+ |
    [1] ---------------+
    
[/code]

最終的には

[code]

    total --------> [5,7,9]
                     ^ ^ ^
    list             | | |
    [0] -------------+ | |
    [1] ---------------+ |
    [2] -----------------+
    
[/code]

になります。

`+=`
では、いちいち新しいオブジェクトを作って代入するという実装方法もあり得たのでしょうが、そうするとメモリの確保と開放が頻繁に起こることになります。numpy
では大きなデータを扱うことが多いので、それは避けたのでしょう。

提示されたコードの append のところを  
`total_list.append(total.copy())`  
と修正すれば、いいでしょう。


CC BY-SA 3.0
2015-10-20T19:57:58.050
17871
2015-10-20T19:57:58.050
3605
17870
answer