当サイトは、アフィリエイト広告を利用しています
Pythonで実装時にリストの編集でよく使うことになる pythonの組み込みの高階関数の
の仕組みと使用方法を調べたので忘備録として残す。
またfilter,mapの仕組みを知る上で重要な概念である
についてまとめる
関数で
の特性を持つものを高階関数と呼ぶ。
は関数を引数としてとるため高階関数に分類される
Pythonの組み込み関数は、標準ライブラリに含まれ、特別なインポートなしで使用できる関数のこと。
高階関数である
はPythonの組み込み関数であるため、特別なインポートなしに使用できる。
※組み込み関数は他にもいろいろある。
反復可能オブジェクトとイテレーターについて
詳しくまとめておく。
反復可能オブジェクトは、要素を順番に取り出すことができるもので
具体的な下記が該当する
イテレーターは、反復可能オブジェクトから生成され、要素を一つずつ取り出すためのオブジェクトのこと
一度に一つの要素しか保持できず、全ての要素を反復した後は再利用できなくなる。
特徴としては下記がある
イテレーターは、next()メソッドを使って次の要素を取得できる
全ての要素を取得すると、StopIteration例外が発生する
# ディクショナリリストusers = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# users リストからイテレーターを生成user_iterator = iter(users)# next() を使って一つずつユーザーを取得print(next(user_iterator)) # 出力: {"user_id": "1", "name": "Tujimura", "age": 11}print(next(user_iterator)) # 出力: {"user_id": "2", "name": "mori", "age": 20}# 次の要素がないため、StopIteration例外が発生try:print(next(user_iterator)) # 50歳のshimadaを取得print(next(user_iterator)) # 70歳のkyogokuを取得print(next(user_iterator)) # ここで StopIteration が発生except StopIteration:print("すべてのユーザーを取得しました") # 出力: すべてのユーザーを取得しました# 実行結果# {'user_id': '1', 'name': 'Tujimura', 'age': 11}# {'user_id': '2', 'name': 'mori', 'age': 20}# {'user_id': '3', 'name': 'shimada', 'age': 50}# {'user_id': '4', 'name': 'kyogoku', 'age': 70}# すべてのユーザーを取得しました
イテレーターは、現在の位置(要素のインデックス)を内部的に記憶している
一度反復が完了すると再利用ができない。
# ディクショナリリストusers = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# users リストからイテレーターを生成user_iterator = iter(users)# 一つずつユーザーを取得(状態が保持される)print(next(user_iterator)) # 出力: {"user_id": "1", "name": "Tujimura", "age": 11}print(next(user_iterator)) # 出力: {"user_id": "2", "name": "mori", "age": 20}# 再度同じイテレーターを使って残りの要素を取得print(list(user_iterator)) # 出力: [{"user_id": "3", "name": "shimada", "age": 50}, {"user_id": "4", "name": "kyogoku", "age": 70}]print(list(user_iterator)) # 出力: [] (すでに全ての要素を取得済み)# 実行結果# {'user_id': '1', 'name': 'Tujimura', 'age': 11}# {'user_id': '2', 'name': 'mori', 'age': 20}# [{'user_id': '3', 'name': 'shimada', 'age': 50}, {'user_id': '4', 'name': 'kyogoku', 'age': 70}]# []
要は同じ値はとれない。
イテレーターは単方向にしか進めず、後戻りはできない。
# ディクショナリリストusers = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# users リストからイテレーターを生成user_iterator = iter(users)# 最初の2ユーザーを取得print(next(user_iterator)) # 出力: {"user_id": "1", "name": "Tujimura", "age": 11}print(next(user_iterator)) # 出力: {"user_id": "2", "name": "mori", "age": 20}# 残りのユーザーを取得(後戻りはできない)print(next(user_iterator)) # 出力: {"user_id": "3", "name": "shimada", "age": 50}print(next(user_iterator)) # 出力: {"user_id": "4", "name": "kyogoku", "age": 70}# 次の要素がないためStopIteration例外が発生try:print(next(user_iterator))except StopIteration:print("もうユーザーはありません") # 出力: もうユーザーはありません# 実行結果# {'user_id': '1', 'name': 'Tujimura', 'age': 11}# {'user_id': '2', 'name': 'mori', 'age': 20}# {'user_id': '3', 'name': 'shimada', 'age': 50}# {'user_id': '4', 'name': 'kyogoku', 'age': 70}# もうユーザーはありません
イテレーターオブジェクトは遅延評価の仕組みを持っているため
必要になるまで値を評価しない。
必要な時にメモリに読み込み、評価して取り出すようになっている。
イテレーターオブジェクトに対して
を使うことでイテレーターオブジェクトを評価して値を取り出すことができる
# ディクショナリリストusers = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# users リストからイテレーターを生成user_iterator = iter(users)# nextで評価して取り出すprint(next(user_iterator)) # 出力: {"user_id": "1", "name": "Tujimura", "age": 11}print(next(user_iterator)) # 出力: {"user_id": "2", "name": "mori", "age": 20}# listで評価して取り出すprint(list(user_iterator)) # 出力: [{"user_id": "3", "name": "shimada", "age": 50}, {"user_id": "4", "name": "kyogoku", "age": 70}]
遅延評価を使うことで、メモリ使用量を最小限に抑え、大量のデータを効率的に扱うことができる。
filterを使ってリストを編集する方法をまとめる。
filter は反復可能オブジェクト(例: リスト)から条件に合う要素を選び出し、
それをイテレーターとして返す
filter関数の構文は下記のようになる
iterater = filter(function, iterable)
第1関数はbooleanを返す関数である必要がある。
また戻り値はイテレーターオブジェクトであるため、listやnextで評価して値を
取り出してやる必要ががある
filterを使ってリストの編集を実装する
# ディクショナリリストusers = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# 年齢が20以上のユーザーをフィルタリングする関数def age_above_20(user):return user["age"] >= 20# filterを使って条件に一致するユーザーを取得filtered_users = filter(age_above_20, users)# 結果をリストに変換して表示print(list(filtered_users))# 実行結果# [# {'user_id': '2', 'name': 'mori', 'age': 20},# {'user_id': '3', 'name': 'shimada', 'age': 50},# {'user_id': '4', 'name': 'kyogoku', 'age': 70}# ]
users = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# 無名関数を使って年齢が20以上のユーザーをフィルタリングfiltered_users = filter(lambda user: user["age"] >= 20, users)# 結果をリストに変換して表示print(list(filtered_users))# 実行結果# [# {'user_id': '2', 'name': 'mori', 'age': 20},# {'user_id': '3', 'name': 'shimada', 'age': 50},# {'user_id': '4', 'name': 'kyogoku', 'age': 70}# ]
mapを使ってリストを編集する方法をまとめる。
mapは反復可能オブジェクト(iterable)の各要素に対して関数を適用し、
その結果をイテレーターとして返す
filter関数の構文は下記のようになる
iterater = map(function, iterable)
戻り値はイテレーターオブジェクトであるため、listやnextで評価して値を
取り出してやる必要ががある
mapを使ってリストの編集を実装する
users = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# 名前付き関数を使って年齢を1歳増やす処理を定義def increment_age(user):return {**user, "age": user["age"] + 1}# 名前付き関数を map に渡して実行updated_users_def = map(increment_age, users)# 結果をリストに変換して表示print(list(updated_users_def))# [{'user_id': '1', 'name': 'Tujimura', 'age': 12}, {'user_id': '2', 'name': 'mori', 'age': 21}, {'user_id': '3', 'name': 'shimada', 'age': 51}, {'user_id': '4', 'name': 'kyogoku', 'age': 71}]
users = [{"user_id": "1", "name": "Tujimura", "age": 11},{"user_id": "2", "name": "mori", "age": 20},{"user_id": "3", "name": "shimada", "age": 50},{"user_id": "4", "name": "kyogoku", "age": 70}]# lambda を使って年齢を1歳増やす処理を map で行うupdated_users_lambda = map(lambda user: {**user, "age": user["age"] + 1}, users)# 結果をリストに変換して表示print(list(updated_users_lambda))# [{'user_id': '1', 'name': 'Tujimura', 'age': 12}, {'user_id': '2', 'name': 'mori', 'age': 21}, {'user_id': '3', 'name': 'shimada', 'age': 51}, {'user_id': '4', 'name': 'kyogoku', 'age': 71}]
リスト内包表記を使えば、上記のfilterやmapと同じことを実装することができるので
二つの違いをまとめておく。
リスト内包表記に関しては下記記事でまとめています
メモリ効率が重要で、大量のデータを処理する場合は、メモリ使用量を抑えられるのでmapやfilterを使う。 一方、小規模データや、すぐに結果が必要な場合は、リスト内包表記の方を使う。
pythonでのmapやfilterの使い方を仕組みから調べて
まとめてみた。
今まではリスト内包表記やジェネレータ式をメインで書いていたので
今後は状況に応じて、filterやmapも使用していきたい