Pythonで作業メモリを節約できるジェネレータ内包表記の使い方のイメージ画像

Pythonで作業メモリを節約できるジェネレータ内包表記の使い方

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

Pythonで作業メモリを節約しプログラムの実行処理速度を高速化させるジェネレータ内包表記について解説。ジェネレータ関数に似ていますが関数ではなく式のためより簡潔なコードで記述でき、膨大な数の演算でも処理できます。

  • Python

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

Pythonのジェネレータ内包表記

内包表記はジェネレータとしても利用することが可能です。今回は『ジェネレータ内包表記』について学習していきます。

『ジェネレータ内包表記』を利用すると『リストから取得した文字列で6文字以下のテキストだけを抽出し小文字化して返す』場合のコードも下記のように簡潔に記述できメモリの消費量を抑えることができるので大量のデータでも処理できます。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


words_gen = (word.lower() for word in words if len(word) < 7)

for text in words_gen:
print(text)

出力結果

python

css
html

それではこのようなコードが自分で記述できるように基本も交えながら学習していきましょう。

ジェネレータ内包表記の特性

イテレータや、ジェネレータ関数、ジェネレータイテレータ等についてまだ覚えていますか。ジェネレータ内包表記の学習に入る前にそれらについての復習を簡単にしておきましょう。

イテレータは反復的にデータのやり取りを行うことができるオブジェクトでしたね。そしてジェネレータ関数はそのイテレータオブジェクトを生成することができる関数です。

ジェネレータ関数を使って作成したオブジェクトはジェネレタイテレータ(≒イテレータ)と呼ばれ、反復的にデータのやり取りを行う際にその都度1つずつデータを生成して返してくれるためメモリを節約でき大容量のデータをあつかう場合には実行処理速度を上げることもできます。

そしてジェネレータ内包表記は内包表記とジェネレータ関数の基本的な考え方をあわせ持ったものです。

関数ではなく式としてコードを簡潔に記述することができ、反復処理を行う際に1つずつデータを生成するためメモリを節約することができるオブジェクトを作ることができるのがジェネレータ内包表記の特性になります。

イテレータや、ジェネレータ関数については下記のページで詳しく解説しています。もし内容を忘れてしまっていた方はいちど確認しておくと良いでしょう。

『内包表記』の基本的な考え方についてはリスト内包表記ページで詳しく解説しています。

他の内包表記やジェネレータ関数との使い分け方

他の内包表記とジェネレータ内包表記の使い分けは扱うデータ量の大きさやメモリを節約したいかどうかで使い分けると良いでしょう。扱うデータ量がかなり大きい場合や、メモリの節約が必要な場合はジェネレータ内包表記を選択します。

ジェネレータ内包表記とジェネレータ関数の使い分けは、内包表記と関数の使い分けと同じ考え方です。関数にするほど複雑な実行処理でない場合や、実行処理を何度も使い回さない場合はジェネレータ内包表記を選択しましょう。

ジェネレータ内包表記の記述方法

ジェネレータ内包表記の記述方法を確認していきましょう。ジェネレータ内包表記の基本的な記述方法は以下のようになります。

  • (新に格納する要素 for 配列内要素 in 配列)

最終的にジェネレータを生成する場合はカッコ『 ( ) 』で挟み、新に格納する要素を最初に記述し、その後は通常のfor文と同じです。カッコ『 ( ) 』で挟むとtupleになるように思いますが実際はジェネレータ内包表記となります

詳細は実際にコードを確認しながら見ていきましょう。

下記のコードはジェネレータ関数を使ってリストから取得した要素をすべて小文字にして返す事例です。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


def word_edit_gen(word_list):
for word in word_list:
yield word.lower()

words_gen = word_edit_gen(words)

print(type(words_gen))

print(next(words_gen))
print(next(words_gen))

出力結果

<class 'generator'>

python
css

上記のコードをジェネレータ内包表記に置き換えると下記のようなサンプルコードになります。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


words_gen = (word.lower() for word in words)

print(type(words_gen))

print(next(words_gen))
print(next(words_gen))

出力結果

<class 'generator'>

python
css

ジェネレータ関数をジェネレータ内包表記に置き換える際に内包表記の式をカッコ『 ( ) 』で挟んでいますが出力されたタイプは『<class 'generator'>』になっていることが確認できます。

ちなみにtupleの内包表記を記述する場合は『(』の前にtupleを宣言する必要があります。間違いやすいので使い分けには注意しましょう。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


words_tup = tuple(word.lower() for word in words)

print(type(words_tup))

出力結果

<class 'tuple'>

ジェネレータ内包表記で利用されるサンプルコード

ジェネレータ内包表記で利用される事例をサンプルコード付きで紹介しておきましょう。

ジェネレータ内包表記でif文も利用する場合のサンプルコード

ジェネレータ内包表記内とif文を合わせて利用する場合の事例です。リストから取得した文字列で6文字以下のテキストだけを抽出し小文字化して返す場合のコードです。

words = ['Python', 'CSS', 'HTML', 'JavaScript']


words_gen = (word.lower() for word in words if len(word) < 7)

for text in words_gen:
print(text)

出力結果

python

css
html

6文字を超えるJavaScriptはピックアップされていないことが確認できます。

今日のdot

ジェネレータ内包表記を利用することでとても簡素なコードでジェネレータイテレータを利用することができます。非常に行数の多いCSVファイルを読み込む場合など利用できるシーンはとても多いのでしっかりとマスターしておきましょう。

最後に実践で迷いがちなそれぞれの使い分けを再度まとめておきます。

他の内包表記とジェネレータ内包表記の使い分け

  •  扱うデータ量がかなり大きい場合や、メモリの節約が必要な場合はジェネレータ内包表記を選択

ジェネレータ内包表記とジェネレータ関数の使い分け

  •  関数にするほど複雑な実行処理でない場合や、実行処理を何度も使い回さない場合はジェネレータ内包表記を選択