Pythonのリスト内包表記の基本と使い方のイメージ画像

Pythonのリスト内包表記の基本と使い方

  • 公開日:2018/11/08
  • 更新日:2018/11/15
  • 投稿者:n bit

Pythonでリストを生成するときに内包表記を利用するとコード内容によっては簡潔に記述することができ無駄な呼び出し処理も抑えられるので実行処理速度を上げることができます。今回はそのリスト内包表記の基本と使い方についての解説です。

  • Python

この記事は約 分で読めます。(文字)

Pythonのリスト内包表記の基本

Pythonには『内包表記』と言う記述方法があります。内包表記はlistでよく使われますがdictやset等でも利用することが可能です。

今回はその中でもリスト内包表記を使って『内包表記』について学習していきましょう。

tupple内の数値要素を2乗して新しいリストを生成する場合を考えてみてください。通常1番に思いつくコードの記述方法は下記のようになるでしょう。

nums = (4,8,9,17,33,68,56)

nums_2xlist = []

for i in nums:
nums_2xlist.append(i ** 2)

print(nums_2xlist)

出力結果

[16, 64, 81, 289, 1089, 4624, 3136]

このようなコードをもっと簡潔なコードで記述することができるのがリスト内包表記です。

リスト内包表記の記述方法

では先程の事例をリスト内包表記を使った記述方法で置き換えていきましょう。リスト内包表記の基本的な記述方法は以下のようになります。

  • [新に格納する要素 for 配列内要素 in 配列]

最終的にリストを生成しますので角カッコ『 [ ] 』で挟み、『新に格納する要素』を最初に記述し、その後は通常のfor文と同じです。言葉で見るよりも実際にコードを見たほうが早いでしょう。

先程の事例をリスト内包表記で置き換えたものです。

nums = (4,8,9,17,33,68,56)

nums_2xlist = [i ** 2 for i in nums]

print(nums_2xlist)

出力結果

[16, 64, 81, 289, 1089, 4624, 3136]

コードは簡潔になり出力結果はfor文で通常通り回した時と同じ値が出力されています。

リスト内包表記で実行処理速度が上がる理由

リスト内包表記を利用することで通常のfor文で回したリストの生成方法と比べて実行処理速度を早めることができます。

実行処理速度が早まる最大の理由は毎回appendを呼び出す必要がないためです。

for文でリストを生成するときには最初に用意した空のリストにappendメソッドを使って新しい要素を1つずつ追加していきます。1つ追加するたびにappendメソッドを呼び出すためそこに若干のロスが発生していました。

リスト内包表記を利用することでその処理がいらなくなるためロスを解消し速度が上がります。

リスト内包表記で実行処理がどれぐらい早くなるのか?

リスト内包表記を利用するとどれぐらい実行処理速度が上がるのか実際に実験してみました。継続しているのは先程のコードを単純に10,000回繰り返したときの平均タイムです。(※1)

from time import time


# 通常コード
nums = (4,8,9,17,33,68,56)

start = time()
for _ in range(10000):

nums_2xlist = []
for i in nums:
nums_2xlist.append(i ** 2)
proc_time = time() - start
print(proc_time)


# リスト内包表記
nums = (4,8,9,17,33,68,56)

start = time()
for _ in range(10000):

nums_2xlist = []
nums_2xlist = [i **2 for i in nums]

proc_time = time() - start
print(proc_time)

出力結果

0.026540517807006836


0.020164012908935547

0.026540517807006836sec から 0.020164012908935547sec にタイムが縮まりました。約24%の速度アップです。

圧倒的に早いと言うわけではありませんが時間がかかるループ処理を行っている場合であれば24%の改善は貴重ですね。

  • ※1:平均タイムを取得するためのコードは別途必要です。今回は説明が複雑になるため平均タイムを取得するためのコードは省いています。

timeモジュールを利用したコードの実行処理を継続する方法は下記のページで詳しく解説しています。

リスト内包表記で利用されるサンプルコード

いくつかリスト内包表記で利用される事例をサンプルコード付きで紹介しておきましょう。

リスト内包表記でif文も利用する場合のサンプルコード

リスト内包表記内でif文も合わせて利用することができます。

tupple内の要素から偶数のみを抽出して新しいリストを生成する事例で考えてみましょう。偶数かどうかは2で割って余りがゼロになるかどうかで判定できます。

i % 2 == 0

まずは通常通りのfor文とif文の組み合わせでappendメソッドを使ってtupple内の要素からリストを生成する場合のコードです。

nums = (4,8,9,17,33,68,56)

nums_2xlist = []

for i in nums:
if i % 2 == 0:
nums_2xlist.append(i)

print(nums_2xlist)

出力結果

[4, 8, 68, 56]

下記のサンプルコードは上記のコードをリスト内包表記を使って置き換えたものです。if文はfor文の後にそのまま続けて記述することで利用できます。

nums = (4,8,9,17,33,68,56)

nums_2xlist = [i for i in nums if i % 2 == 0]

print(nums_2xlist)

出力結果

[4, 8, 68, 56]

リスト内包表記でfor文を入れ子にする場合のサンプルコード

2つの配列を使って新しいリストの要素値を求める場合はfor文を入れ子にして回す必要があります。

2つの配列の値を掛け合わして2次元配列の新しいリストを生成してみましょう。

下記は通常のコード事例です。

nums1 = (4,8,9,17,33,68,56)

nums2 = (3,7,10)
nums_multipl_list = []

for n1 in nums1:
element_list = []
for n2 in nums2:
element_list.append(n1 * n2)
nums_multipl_list.append(element_list)

print(nums_multipl_list)

出力結果

[[12, 28, 40], [24, 56, 80], [27, 63, 90], [51, 119, 170], [99, 231, 330], [204, 476, 680], [168, 392, 560]]

上記のコードをリスト内包表記を使って置き換えてみましょう。if文の時と違って少し複雑に感じるかもしれませんが最初の内包表記から取得した要素の部分で再度リスト内包表記を記述し掛け合わせているだけです。

nums1 = (4,8,9,17,33,68,56)

nums2 = (3,7,10)
nums_multipl_list = [[n1 * n2 for n2 in nums2] for n1 in nums1]

print(nums_multipl_list)

出力結果

[[12, 28, 40], [24, 56, 80], [27, 63, 90], [51, 119, 170], [99, 231, 330], [204, 476, 680], [168, 392, 560]]

このケースの場合はコード量をぐっと減らすことができますし可読性も上がります。慣れてしまうとコード内で何が実行されているのかもこちらの記述方法の方が理解しやすいです。

今日のdot

リスト内包表記はとても便利ですがあまり複雑な内容を記述してしまいますと可読性が下がります。ループ処理にかかる総時間がそこまで長くない場合は速度を求めたところで微々たる世界でしょう。

そのため今後のミスや管理のしやすさなどを考えた場合は無理にリスト内包表記を利用せず通常通りの記述方法で可読性を保つ方が良いといえます。

利用するケースによってはリスト内包表記はとても使い勝手が良い記述方法なので利用場所を選びながら活用していきましょう。