【図解で詳解】Pythonの基礎文法_内包表記によるオブジェクトの作成

スポンサーリンク
Pythonの基礎文法(内包表記) Python

【図解で詳解】Pythonの基礎文法_内包表記によるオブジェクトの作成

Pythonの基礎文法を図を用いて分かりやすく解説していきます。

今回はPythonの内包表記というイテラブルなオブジェクトからリスト・辞書・セットオブジェクトを作成する方法について解説していきます。(イテラブルとはオブジェクトに含まれる要素を順次1個ずつ取り出すことができるオブジェクトになります。)

リストと辞書に関しては次の記事を参考にして下さい。

内包表記とは他言語にはないPython特有の書き方でfor-in構文と[],{}を組み合わせてリスト・辞書・セットオブジェクトの生成を1ステートメントで簡潔に書くことができます。Pythonプログラマの間では当たり前のように使われている書き方です。

したがって、コードを書く、他の人の書いたコードを解読するといった場合はこの内包表記の書き方を知っておく必要があります

また、Python公式ドキュメントの内包表記に関する定義は以下になりますので必要に応じて参照してください。

Python公式ドキュメント(リストの内包表記)の引用

https://docs.python.org/ja/3/tutorial/datastructures.html#list-comprehensions
スポンサーリンク

1. 内包表記によるオブジェクトの生成

Python_基礎構文(List)_内包表記

内包表記によって各種オブジェクトを生成する方法には、いくつかのパターンがありますので順番に解説していきます。

1.1 内包表記の基本形

内包表記の基本書式を作成するオブジェクトごとに示します。対象のオブジェクトごとに[],{}や式の部分に違いがありますが基本的な作り方は同じです。

内包表記の基本形

リスト内包表記

for 変数 in イテラブル

辞書の内包表記

{ キー:式(値)for キー in イテラブル }

セットの内包表記

{for 変数 in イテラブル }

内包表記の処理手順の概略を図示にすると次のようになります。

まず、リストの内包表記の概略図です。セットの内包表記はリストとほぼ同様で、[]で囲むか、{}で囲むかの違いしかありませんので省略しています。(図1)

内包表記の基本_リスト_セット
図1 リストの内包表記の基本

次に辞書の内包表記です。リスト(セット)との違いは「式」の部分が辞書の仕様「{キー:値}」になっただけです。(図2)

内包表記の基本_辞書
図2 辞書の内包表記の基本

それでは、実使用コードで確認してみましょう。次は最も基本的な使い方としてイテラブルの部分に「リスト」をつかって、リスト、セット、辞書の内包表記による各オブジェクトを作成している例です。

# イテラブルなオブジェクトに「リスト」を指定した場合
# リストの内包表記の基本形➀

nums = [1, 2, 3, 4, 5]

nums_double = [ num * 2 for num in nums ] # リストnumsの各要素を2倍にしたリストを作成する
print(nums_double) # >>[2, 4, 6, 8, 10] 新しいリストが作成された

#-----------------------------------------------------------------------
# セットの内包表記の基本形➀

nums = [1, 2, 3, 4, 5]

nums_double = { num * 2 for num in nums } # リストnumsの各要素を2倍にしたセットを作成する
print(nums_double) # >>{2, 4, 6, 8, 10} 新しいセットが作成された

#-----------------------------------------------------------------------
# 辞書の内包表記の基本形➀

keys = ['apple', 'orange', 'pine','avocado']

dict_out = { key:len(key) for key in keys } # リストkeysの各要素をキーとし、キーの長さを値とする辞書を作成する
print(dict_out) # >>{'apple': 5, 'orange': 6, 'pine': 4, 'avocado': 7}  新しい辞書が作成された

次は、For-in構文と一緒に使われることが多い、rangeオブジェクトをイテラブルに設定リスト・辞書の内包表記の例です。

# イテラブルなオブジェクトに「rangeオブジェクト」を指定した場合
# リストの内包表記の基本形➁

nums = [ num for num in range(1, 5) ] # 1~4rangeオブジェクトからリストを作成する
print(nums) # >>[1, 2, 3, 4]

#-----------------------------------------------------------------------
# 辞書の内包表記の基本形➁

dict_out = { key : (key * 2) for key in range(1, 5) } # 1~4rangeオブジェクトからキーと値を要素とする辞書を作成する
print(dict_out) # >>{1: 2, 2: 4, 3: 6, 4: 8}

また、文字列(str型)もイテラブルに指定することもできます。

# イテラブルなオブジェクトに「strオブジェクト」を指定した場合
# リストの内包表記の基本形➂

str_list = [ str + "_class" for str in "ABCD" ] # 文字列から文字を取り出してリストを作成する
print(str_list) # >>['A_class', 'B_class', 'C_class', 'D_class']

#-----------------------------------------------------------------------
# 辞書の内包表記の基本形➂

dict_out = { key : ord(key) for key in "ABCD" } # 文字列からキーとキーの文字コードを要素とする辞書を作成する
print(dict_out) # >>{'A': 65, 'B': 66, 'C': 67, 'D': 68}

そして、最後にzipオブジェクトをつかって2つの変数にアンパックしている応用事例を示します。For文の変数の部分には複数個の変数を置くことができます。

# イテラブルなオブジェクトに「zipオブジェクト」を指定した場合
# リストの内包表記の基本形➃

str1 = ["A", "B", "C"]
str2 = ["_a", "_b", "_c"]

# zipオブジェクトを展開して2つの変数に格納して、連結したものを要素とするリストを作成する
str12 = [ s1 + s2 for s1, s2 in zip(str1, str2) ]
print(str12) # >>['A_a', 'B_b', 'C_c']

以上で、内包表記の基本形の解説は終わりです。

コード例を見て、既にお気づきかもしれませんが、内包表記といってもやっていること(できることは)For-in構文と同じです。1行で簡潔に可読性よく各オブジェクトを作成することが内包表記の目的です。

1.2 For文句2重化による内包表記

内包表記の基本形をすこし発展させたFor-in句の2重化(ネスト)して使う方法もあります。

たとえば、「リストの要素がリスト」・「文字列が要素のリスト」であったり、イテラブルな要素をもつイテラブルなオブジェクトを効率的に展開し、新たなオブジェクトを作成することができるようになります。

この2重化した内包表記も、リスト・セット・辞書の3種類のオブジェクトに応用することができます。以下に書式を示します。

リストの内包表記(for文句の多重化)

リスト内包表記

for 変数A in イテラブル for 変数B in 変数A

辞書の内包表記

キー:式(値) for 変数 in イテラブル for キー in 変数

セットの内包表記

for 変数A in イテラブル for 変数B in 変数A

概略を図示すると次のようになります。

リスト・セット・辞書ともにfor-in句が2重化されている部分が先の基本形とはことなりますのでリストを例にしています。(図3) for-in句が並んだ場合は、まず左側のfor-in句が最初に展開され、次に右側に引き継がれるといった処理の流れになります。

図3 リストの内包表記(for-in句のネスト)

内包表記のネスト構造
図3 リストの内包表記(for-in句のネスト)

実使用コードで確認したほうが理解しやすいと思います。イテラブルなオブジェクトとして「リストの要素がリスト」と「文字列が要素のリスト」の2つについて内包表記で展開する例になっています。for-in句の処理順に着目してください。

# For文句の2重化による内包表記


# イテラブルなオブジェクト(リストを要素にもつリストの場合)
numbers = [ [1, 2], [3, 4], [5, 6] ]

# リストの内包表記(For-in句のネスト型)➀

list_result = [ num_b*2 for num_a in numbers for num_b in num_a ]
print(list_result) # >>[2, 4, 6, 8, 10, 12]

#--------------------------------------------------------------------------
# セットの内包表記(For-in句のネスト型)➀

set_result={ num_b*2 for num_a in numbers for num_b in num_a }
print(set_result) # >>[2, 4, 6, 8, 10, 12]

#--------------------------------------------------------------------------
# 辞書の内包表記(For-in句のネスト型)➀

dict_result={num_b : 'No.'+str(num_b)  for num_a in numbers for num_b in num_a}
print(dict_result) # >>{1: 'No.1', 2: 'No.2', 3: 'No.3', 4: 'No.4', 5: 'No.5', 6: 'No.6'}


#--------------------------------------------------------------------------
# イテラブルなオブジェクト(文字列を要素にもつリストの場合)
strings = ['AB', 'CD', 'EF']

# リストの内包表記(For-in句のネスト型)➁
list_result2 = [ str_b * 2  for str_a in strings for str_b in str_a ]
print(list_result2) # >>['AA', 'BB', 'CC', 'DD', 'EE', 'FF']

また、別の事例として、内包表記の内部にさらに[]をつかって処理の順序を明示的に変更することでfor-in句の処理順序を変更することができます。次の例がそれで、まず外側(右側)のfor-in句が最初に展開され、次に内側(左側)が処理されるといった順序になります。

これによりもとのオブジェクト構造を変更することなく新たなオブジェクトをつくることが可能となります。

# For文句の2重化による内包表記

# イテラブルなオブジェクト(リストを要素にもつリストの場合)
numbers = [ [1, 2], [3, 4], [5, 6] ]

# リストの内包表記(For-in句のネスト型)➂
list_result=[ [ num_b*2 for num_b in num_a ] for num_a in numbers ] # 外側の[]内のfor-in句が優先される
print(list_result) # >>[[2, 4], [6, 8], [10, 12]]

以上、内包表記のfor-in句のネスト型についての解説しました。基本型に比べると複雑で使用頻度は低くなりますが、イテラブルオブジェクトの形態によっては1行で簡潔にコードを記述する、このようなスタイルがあることを覚えておきましょう。

1.3 if文条件式付きの内包表記

内包表記にif文による条件式を付加することで、設定した条件を満たす場合に限り、新規オブジェクトの要素として追加するといったことができるようになります。

つまり、1.1項や1.2項のように元のイテラブルの全要素を評価・追加するのではなく、特定の条件でフィルタリングされた要素のみを評価・追加します。以下に書式を示します。

リストの内包表記(条件式付き)

リスト内包表記

for 変数 in イテラブル if 条件式

辞書の内包表記

{ キー式(値)for キー in イテラブル if 条件式 }

セットの内包表記

{ for 変数 in イテラブル if 条件式  }

概略を図示すると次のようになります。

内包表記のif句条件文付き
図4 リストの内包表記(if文句条件式付き)

条件式を含んだ内包表記の実使用例を示します。if文句で条件に合った要素で新たなリストを作成しています。

# 条件式付き内包表記(1)

# リストの内包表記(条件式付き)➀

# 条件式(0以上3未満)が成り立つ要素を2倍して新たなリストを作る
numbers = [-1, 0, 1, 2, 3, 4, 5]
result = [ num * 2 for num in numbers if (0 <= num < 3) ]
print(result) # >>[0, 2, 4]

# 条件式(文字数が5文字)が成り立つ要素をもつ新たなリストを作る
words = ['Japan', 'America', 'Chine', 'England']
result = [ word for word in words if len(word) == 5 ]
print(result) # >>['Japan', 'Chine']

#-------------------------------------------------------------------
# 辞書の内包表記(条件式付き)➀

words = ['Japan', 'America', 'Chine', 'England']
result = { key : str(len(key))+'文字' for key in words if len(key) == 5 }
print(result) # {'Japan': '5文字', 'Chine': '5文字'}

また、if文句は1つだけではなく、複数個指定することができます。その場合は、次のようにif文句をスペースを空けて必要数並べることができます。If文句間は;(セミコロン)や,(カンマ)などで区切ることはできません。可読性が低下するので2個程度にしておきましょう。

# 条件式付き内包表記(2)

# リストの内包表記(条件式付き)➁

# 条件式(5以上の偶数)が成り立つ要素をもつ新たなリストを作る
numbers = [4, 12, 21, 32, 8, 6, 11, 16]
result = [ num for num in numbers if num>=5 if num%2==0 ]
print(result) # >>[12, 32, 8, 6, 16]

2. まとめ

いかがでしたでしょうか?

今回は、Pythonの内包表記について解説をしました。内包表記は他のプログラミング言語には見られない特殊な書き方なので慣れるまでは戸惑いますが、複数行の処理を1ステートメントに記述できるためコードがスッキリとし、可読性が高まります

また、処理が少し速まるというメリットもありPythonでは好んで使われる書き方の一つとなります。

今回の記事を是非、お役立てくださいますと幸いです。

最後までお読みいただきありがとうございました。

タイトルとURLをコピーしました