もし場違いなら申し訳ないのですが、ちょっとpythonでわからないことがあるのでよければ誰か教えていただけませんか?
複数の要素に空のリストを同時に設定して一つの要素にappendや代入すると全部の要素に適用されて困っています。以下が例です。
IN
hoge=dict.fromkeys(“key”,dict.fromkeys([“max”,”min”,”mean”],[]))
hoge[“e”][“max”].append(1)
print(hoge)
hoge[“e”][“max”]=2
print(hoge)
OUT
{‘e’: {‘max’: [1], ‘mean’: [1], ‘min’: [1]},
‘k’: {‘max’: [1], ‘mean’: [1], ‘min’: [1]},
‘y’: {‘max’: [1], ‘mean’: [1], ‘min’: [1]}}
{‘e’: {‘max’: 2, ‘mean’: [1], ‘min’: [1]},
‘k’: {‘max’: 2, ‘mean’: [1], ‘min’: [1]},
‘y’: {‘max’: 2, ‘mean’: [1], ‘min’: [1]}}
以前から空のリストを複数の要素に同時に代入してappendしたり演算すると全部に適用されて意味がわからず困っています。原因は何なのか、対処法はなんなのか教えていただけませんか?ネットで調べてみてもよくわかりませんでした…。また、このことが解説されている文書などあれば合わせて教えていただけると幸いです。よろしくお願いします。
似非プログラマ 間違いなく言えることは、hoge[“k”], hoge[“e”], hoge[“y”] が全て同じアドレスを参照していると言うことですが、言語仕様としてはおかしいですよね。私も時間があったら調べてみます。 2013/11/29
Ken Senoo コメントありがとうございます。こちらの動作環境はpython2.7系です。
私がやりたいことは、”key”のところを[“NO”, “CO”]といったリストにして、辞書で配列?を用意してあとから該当する要素(NOなど)の[“min”]などを指定して値を追加することです。
+Takashi Unuma さんのご指摘のように、以下のようにdict.fromkeys([“k”,”e”,”y”],xxx)としてもやはり全要素に値が設定されてしまいます。
IN: hoge=dict.fromkeys([“k”,”e”,”y”],[ ]); hoge[“e”].append(1); print(hoge)
OUT: {‘e’: [1], ‘k’: [1], ‘y’: [1]}
おそらくリスト[ ]が原因でないかと思っています。
以前にも空リスト作成時に同様の問題があり、[[ ]]*3のようにするとappend時に全要素に値が設定されます。
IN: a=[[ ]]*3; a[0].append(1); print(a)
OUT: [[1], [1], [1]]
このときはリスト内包表記を使って空リストを作成して解決しました。
IN: a = [[ ] for i in range(3)]; a[0].append(1); print(a)
OUT: [[1],[ ],[ ]]
リストは便利なんですが、空リストの作成が厄介です。 2013/11/29
Ken Senoo やはり同じでした(-1でも同様)。
In: hoge=dict.fromkeys([“k”,”e”,”y”],[None]); hoge[“e”].append(1); print(hoge)
Out: {‘e’: [None, 1], ‘k’: [None, 1], ‘y’: [None, 1]}
念のためPython3.2でもこれと同じコードを試しましたが同じでした。
追記(.append( ))する必要があるので初期値にリスト[ ]を使っていますが、他の方法でも追記できるならそれでもOKです。 2013/11/29
Ken Senoo この問題が解決すれば後々かなり楽なので何回でもやりますよ(笑)。
試したところ、やはり同じようです…。
IN: hoge=dict.fromkeys([“k”,”e”,”y”],[None,None,None]); hoge[“y”].append(1); print(hoge)
OUT: {‘y’: [None, None, None, 1], ‘k’: [None, None, None, 1], ‘e’: [None, None, None, 1]} 2013/11/29
Ryuji Iwata 今回のケースの対処法は「dict.fromkeys()で生成しない」かと。オブジェクト(今回はリスト)を指定すると「参照」されてしまうため、毎回「生成」する記述にすれば回避できるかと。(的外れならスミマセン)
hoge = {}
for x in “key”:
hoge[x] = {‘max’: [], ‘mean’: [], ‘min’: []}
hoge[“e”][“max”].append(1)
print(hoge)
hoge[“e”][“max”]=2
print(hoge)
OUT
{‘y’: {‘max’: [], ‘min’: [], ‘mean’: []},
‘k’: {‘max’: [], ‘min’: [], ‘mean’: []},
‘e’: {‘max’: [1], ‘min’: [], ‘mean’: []}}
{‘y’: {‘max’: [], ‘min’: [], ‘mean’: []},
‘k’: {‘max’: [], ‘min’: [], ‘mean’: []},
‘e’: {‘max’: 2, ‘min’: [], ‘mean’: []}} 2013/11/30
Ken Senoo +Ryuji Iwata さん。ありがとうございます!やはり個別に生成するしかありませんか…。それがわかっただけで自分にとって非常に勉強になりました。
独立した空のリストを作る関数が標準であれば何かと便利だと思うのですけどね。実装されるまでは(ないかもしれませんが(苦笑))forや内包表記で空のリストを作ることにします。
以下は自分のメモとして、今回のケースを辞書内包表記(python 2.7以降でのみ有効)で作ってみました。
hoge={x:{i:[ ] for i in [“max”, “min”, “mean”]} for x in “key”}
お答えくださった+Takashi Nomura さんと+似非プログラマさん もありがとうございました。おかげさまで解決しました。 2013/11/30
似非プログラマ StackOverFlow にも似たようなことが書いてありました。やはり結論は「fromkeys を使うな」です。
http://stackoverflow.com/questions/8174723/dictionary-creation-with-fromkeys-and-mutable-objects-a-surprise 2013/11/30
Ken Senoo 既出の問題でしたか…。調査不足でした。対処法としては、やはり個別に生成するしかないのですね。
お調べくださってありがとうございます! 2013/11/30
関連