[解決済み] リストの変更が不意にサブリスト全体に反映されたリスト
質問
Pythonでリストを作成する必要があったので、次のように入力しました。
my_list = [[1] * 4] * 3
リストはこんな感じでした。
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
そして、一番内側の値の一つを変更しました。
my_list[0][0] = 5
これで、私のリストは次のようになります。
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
というのは、私が望んでいたものでも、期待していたものでもありません。どなたか、何が起こっているのか、どうすれば回避できるのか、説明していただけませんか?
解決方法は?
と書くと
[x]*3
というリストが得られます。
[x, x, x]
. つまり、3つの参照があるリストで、同じ
x
. この1つの
x
は、その3つの参照先すべてから見えるようになります。
x = [1] * 4
l = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
f"id(l[0]): {id(l[0])}\n"
f"id(l[1]): {id(l[1])}\n"
f"id(l[2]): {id(l[2])}"
)
# id(l[0]): 140560897920048
# id(l[1]): 140560897920048
# id(l[2]): 140560897920048
x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"l: {l}")
# l: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]
これを解決するには、各ポジションで新しいリストを作成するようにする必要があります。その方法のひとつは
[[1]*4 for _ in range(3)]
を再評価します。
[1]*4
の代わりに、毎回評価し、1つのリストに対して3つの参照を行います。
と疑問に思うかもしれませんが
*
は、リスト内包のように独立したオブジェクトを作ることができません。それは、乗算演算子
*
は、式を見ることなく、オブジェクトに対して操作します。式は見えません。
*
を掛け合わせると
[[1] * 4]
を3で割ったものです。
*
は 1 要素のリスト
[[1] * 4]
は評価されません。
[[1] * 4
の式テキストを表示します。
*
は、その要素のコピーを作成する方法も、再評価する方法も知らない。
[[1] * 4]
そして、一般的には、要素をコピーする方法さえないかもしれません。
唯一の選択肢
*
は、新しいサブリストを作ろうとするのではなく、既存のサブリストへの新しい参照を作ることです。それ以外の方法は、一貫性がないか、根本的な言語設計の決定から大きく再設計する必要があります。
これに対して、リスト内包は、繰り返しごとに要素式を再評価する。
[[1] * 4 for n in range(3)]
は再評価されます。
[1] * 4
毎回同じ理由で
[x**2 for x in range(3)]
再評価
x**2
を毎回使用します。の評価は毎回
[1] * 4
は新しいリストを生成するので、リスト内包はあなたが望んだとおりの働きをします。
ちなみに
[1] * 4
の要素もコピーされません。
[1]
しかし、整数は不変なので、それは問題ではありません。のようなことはできません。
1.value = 2
を2にすることができます。
関連
-
[解決済み】NameError: 名前 'self' が定義されていません。
-
[解決済み】 'numpy.float64' オブジェクトは反復可能ではない
-
[解決済み] リストのリストからフラットなリストを作るには?
-
[解決済み] 割り当て後にリストが予期せず変更されました。その理由と防止策を教えてください。
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み] 最近のPythonでカスタム例外を宣言する適切な方法?
-
[解決済み] Pythonの「名前付きタプル」とは何ですか?
-
[解決済み] Pythonで一定の大きさの空リストを作成する
-
[解決済み】pandasでカラムの種類を変更する
-
[解決済み】Pythonの「private」メソッドは、なぜ実際にはprivateではないのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
opencvとpillowを用いた顔認証システム(デモあり)
-
python string splicing.join()とsplitting.split()の説明
-
Python interpreted model libraryによる機械学習モデル出力の可視化 Shap
-
Python Pillow Image.save jpg画像圧縮問題
-
FacebookオープンソースワンストップサービスpythonのタイミングツールKats詳細
-
[解決済み] builtins.TypeError: strでなければならない、bytesではない
-
[解決済み] TypeError: 'DataFrame' オブジェクトは呼び出し可能ではない
-
[解決済み】Flask ImportError: Flask という名前のモジュールがない
-
[解決済み】ValueError: xとyは同じサイズでなければならない
-
[解決済み] [Solved] リストのリストを初期化するコードは、なぜリスト同士をリンクしているように見えるのでしょうか?重複