PythonでLoop文を書く際、どうしても基本的なfor loopを使用しがちなので、現状の理解具合を整理。
基礎のfor loop
>>> L = [1, 3, 5, 7, 9] >>> for i in range(len(L)): ... L[i] += 10 ... >>> L [11, 13, 15, 17, 19]
最初に学ぶfor loopはこんな感じ。
List comprehensionによるfor loop
最近はこの形のfor loopをよく見かけます。
>>> L = [1, 3, 5, 7, 9] >>> L = [x + 10 for x in L] >>> L [11, 13, 15, 17, 19]
この2つのloopは殆ど同じ挙動をするので、List comprehensionで記載した方がコードはシンプルになるし、実行速度も大きく改善されます。
しかし、「殆ど」同じ挙動をする、と書いた様に、以下の点には注意。
元のリストへの影響が異なる
基礎のfor loopでは元のリストが書き換えられるが、List comprehensionでloopした場合、新しいリストが作られる。
基礎のfor loopでidを確認
>>> L = [1, 3, 5, 7, 9] >>> A = L # 変数AにLを代入 >>> id(L) 4384850240 >>> id(A) 4384850240 >>> for i in range(len(L)): ... L[i] += 10 ... >>> L [11, 13, 15, 17, 19] >>> A [11, 13, 15, 17, 19] >>> id(L) 4384850240 >>> id(A) 4384850240 # 同id = 元のリストが置き換わっている。
この様に、LとAのidが同じ事から、最初のリストLが書き換えられている事が分かる。
List comprehensionでidを確認
>>> L = [1, 3, 5, 7, 9] >>> A = L # 同じく変数AにLを代入 >>> L [1, 3, 5, 7, 9] >>> A [1, 3, 5, 7, 9] >>> id(L) 4384686160 >>> id(A) 4384686160 # 同じ[1, 3, 5, 7, 9]を参照している >>> L = [x + 10 for x in L] # List conprehensionでのloop >>> L [11, 13, 15, 17, 19] >>> A [1, 3, 5, 7, 9] # L ≠ A >>> id(L) 4384545040 >>> id(A) 4384686160 # Lは新しいリスト、Aは元のリストを参照している。
LとAが別の物を見ている事が分かる。
Lは新しいリスト、Aは元のリストを見ている。
(2020/1/12 注:LとAの順番が紛らわしかった為修正)
list comprehensionでは、listを作る際のblacket、square blacket[]を使用する所から、オリジナルのリストを書き換えるのでは無く、リストを新たに作り出す。
考えられる問題
例えばオリジナルのリスト[1, 3, 5, 7, 9]を別の変数で参照して別の処理をしていた場合、List comprehensionでloopした場合はオリジナルのリストは変更されない事に注意しておきたい。
必要な場合はList comprehensionでloopした後に改めてL = Aとする事で参照し直すと良い。
自分の理解をまとめようと書き出したら、どんどん新たに知る事実が出てきてしまったので、2に続く。
コメント