Pythonで
— Hideyuki Tanaka (@tanakh) 2018年3月26日
> a = [[0]*3]*3
> a[0][0] = 1
が
> [[1,0,0],[0,0,0],[0,0,0]]
でも
> [[1,1,1],[1,1,1],[1,1,1]]
でもなく、
> [[1,0,0],[1,0,0],[1,0,0]]
になるのは最高にクッソって感じはする。
げ、rubyもそうだ
— Dan Kogai (@dankogai) 2018年3月27日
% irb
irb(main):001:0> a = [[0]*3]*3
=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
irb(main):002:0> a[0][0] = 1
=> 1
irb(main):003:0> a
=> [[1, 0, 0], [1, 0, 0], [1, 0, 0]] https://t.co/FAPlhobycZ
この事態を Python で避ける方法。
まず、なぜそうなるかということを書こうと思ったら、既出。
つまりこうなってると
— Dan Kogai (@dankogai) 2018年3月27日
a = [0,0,0]
aa = [a,a,a] # aa[0][0] === aa[1][0] === aa[2][0]
aa[0][0] = 1 # a[0] = 1
Python 3 に 「===」演算子はないから、わかりやすくイメージ図を追加。
(MyScript Nebo(iPad アプリ)、Nebo(Windows アプリ)を使って描いてみた。まだダイアグラムの描画をうまく使えるようになってない…)
BIF(built-in function) の id 関数でも確認。
コード(Emacs)
Python 3
#!/usr/bin/env python3 a = [[0] * 3] * 3 print(f'a: {a}') for i, t in enumerate(a): print(f'a[{i}]: {id(t)}') print() a[0][0] = 1 print(f'a: {a}') for i, t in enumerate(a): print(f'a[{i}]: {id(t)}') a = [[0] * 3 for _ in range(3)] print(f'a: {a}') for i, t in enumerate(a): print(f'a[{i}]: {id(t)}') print() a[0][0] = 1 print(f'a: {a}') for i, t in enumerate(a): print(f'a[{i}]: {id(t)}')
入出力結果(Terminal, Jupyter(IPython))
$ ./sample1.py a: [[0, 0, 0], [0, 0, 0], [0, 0, 0]] a[0]: 4387831176 a[1]: 4387831176 a[2]: 4387831176 a: [[1, 0, 0], [1, 0, 0], [1, 0, 0]] a[0]: 4387831176 a[1]: 4387831176 a[2]: 4387831176 a: [[0, 0, 0], [0, 0, 0], [0, 0, 0]] a[0]: 4387940680 a[1]: 4387828872 a[2]: 4387942152 a: [[1, 0, 0], [0, 0, 0], [0, 0, 0]] a[0]: 4387940680 a[1]: 4387828872 a[2]: 4387942152 $
ということで、どのように解決するか。
コード(Emacs)
Python 3
#!/usr/bin/env python3 a = [[0] * 3 for _ in range(3)] a[0][0] = 1 print(a)
入出力結果(Terminal, Jupyter(IPython))
$ ./sample.py [[1, 0, 0], [0, 0, 0], [0, 0, 0]] $
リスト内包表記を使えば、リストの各要素(リスト)が同じものではなく、別々のリストってことがはっきりするし、優先順位を気にする必要もなくなる(し、読みやすくなる(?))。
(タイプ数は多くなるけど...>_<)
0 コメント:
コメントを投稿