初めに
paizaを触って1か月、レート2000に到達しました。
備忘録を兼ねて、覚えておくと良さげなPython3のポイントについて不定期に投下してみます。
使用Version:Python 3.11.2
二次元リストの初期化
二次元リストを初期化する際は基本下記のような処理を使うようにしたいです。
[[0]*3 for _ in range(4)]
下記はサンプルコードです。4×3サイズの0埋めリストの初期化になります。
test.py
# 二次元リストnizi_listの初期化
ROWS,COLUMNS=4,3
nizi_list = [[0]*ROWS for _ in range(COLUMNS)]
print("■nizi_listの初期化後の中身");print(*nizi_list, sep='\n');print()
# 各リストのオブジェクトIDの確認
print("■nizi_listの各リストのオブジェクトIDの確認")
for i in range(COLUMNS):
print("nizi_list[%d]のオブジェクトID: %d"%(i,id(nizi_list[i])))
print()
# 二次元リストnizi_listの要素の変更
nizi_list[0][1] = 1
print("■nizi_list[0][1]の値変更後の中身");print(*nizi_list, sep='\n');print()
test.py実行結果のログ
■nizi_listの初期化後の中身
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
■nizi_listの各リストのオブジェクトIDの確認
nizi_list[0]のオブジェクトID: 1936982372288
nizi_list[1]のオブジェクトID: 1936982416256
nizi_list[2]のオブジェクトID: 1936982411712
■nizi_list[0][1]の値変更後の中身
[0, 1, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
NG例
明確な意図がない限り、普段やってはいけないのが下記表現です。
[[0]*3] * 4
これは初期化処理の記述量が少なく、一見楽になったように見えます。
ですが各要素の値を変更する際に狙いどおりの挙動にならないことが殆どでしょう。
test.py
#二次元リストnizi_listの初期化
ROWS,COLUMNS=4,3
nizi_list = [[0]*ROWS] * COLUMNS
print("■nizi_listの初期化後の中身");print(*nizi_list, sep='\n');print()
#(以下略)
test.py実行結果のログ
■nizi_listの初期化後の中身
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
■nizi_listの各リストのオブジェクトIDの確認
nizi_list[0]のオブジェクトID: 2893548518592
nizi_list[1]のオブジェクトID: 2893548518592
nizi_list[2]のオブジェクトID: 2893548518592
■nizi_list[0][1]の値変更後の中身
[0, 1, 0, 0]
[0, 1, 0, 0]
[0, 1, 0, 0]
-
nizi_list[0][1]
のみを変更したつもりが、nizi_list[1][1]
とnizi_list[2][1]
も同時に変更されてしまいました。- これは
nizi_list[0]
~nizi_list[2]
が全て同じオブジェクトとして定義されたためです。 - オブジェクトIDはid関数を用いることで調べることができます。
- これは
- 競技プログラミングの場ではあえてこの初期化方法を使う場面は限られるでしょう。
補足
Python 3.11.2 Documentation(プログラミング FAQ)にて本記事と同内容の説明が記載されています。
https://docs.python.org/ja/3/faq/programming.html#how-do-i-create-a-multidimensional-list
(コメントにてご教示いただきました。ありがとうございます。)