Python高階関数完全マスター – map、filter、reduceから関数型プログラミングまで
Python高階関数は、関数を引数として受け取ったり、関数を戻り値として返したりする強力な機能です。本記事では、Pythonの高階関数の基本から応用まで、実践的なサンプルコードとともに詳しく解説します。
高階関数とは
高階関数(Higher-Order Function)は、以下の特徴を持つ関数です:
- 他の関数を引数として受け取る
- 関数を戻り値として返す
- 関数を変数に代入して操作する
これにより、コードの再利用性と可読性が大幅に向上します。
基本的な高階関数
1. map()関数
リストの各要素に関数を適用して新しいリストを作成します。
# 基本的な使用例
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# 関数を定義して使用
def double(x):
return x * 2
doubled = list(map(double, numbers))
print(doubled) # [2, 4, 6, 8, 10]
2. filter()関数
条件に合致する要素のみを抽出します。
# 偶数のみを抽出
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# 空文字列を除外
words = ["hello", "", "world", "", "python"]
filtered = list(filter(None, words))
print(filtered) # ['hello', 'world', 'python']
3. reduce()関数
リストの要素を累積的に処理して単一の値を返します。
from functools import reduce
# 合計を計算
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x + y, numbers)
print(total) # 15
# 最大値を取得
maximum = reduce(lambda x, y: x if x > y else y, numbers)
print(maximum) # 5
組み込み高階関数の活用
1. sorted()関数
# カスタムキーでソート
students = [("太郎", 85), ("花子", 92), ("次郎", 78)]
sorted_by_score = sorted(students, key=lambda x: x[1])
print(sorted_by_score) # [('次郎', 78), ('太郎', 85), ('花子', 92)]
# 逆順ソート
reversed_sort = sorted(students, key=lambda x: x[1], reverse=True)
print(reversed_sort) # [('花子', 92), ('太郎', 85), ('次郎', 78)]
2. max()とmin()関数
# カスタムキーで最大値・最小値を取得
words = ["python", "java", "javascript", "go"]
longest = max(words, key=len)
shortest = min(words, key=len)
print(f"最長: {longest}, 最短: {shortest}") # 最長: javascript, 最短: go
3. any()とall()関数
# すべての要素が条件を満たすかチェック
numbers = [2, 4, 6, 8, 10]
all_even = all(x % 2 == 0 for x in numbers)
print(all_even) # True
# いずれかの要素が条件を満たすかチェック
mixed = [1, 3, 5, 6, 7]
any_even = any(x % 2 == 0 for x in mixed)
print(any_even) # True
カスタム高階関数の作成
1. 関数を引数として受け取る高階関数
def apply_operation(numbers, operation):
return [operation(x) for x in numbers]
def square(x):
return x ** 2
def cube(x):
return x ** 3
numbers = [1, 2, 3, 4, 5]
squared = apply_operation(numbers, square)
cubed = apply_operation(numbers, cube)
print(f"2乗: {squared}") # [1, 4, 9, 16, 25]
print(f"3乗: {cubed}") # [1, 8, 27, 64, 125]
2. 関数を返す高階関数
def create_multiplier(n):
def multiplier(x):
return x * n
return multiplier
# 2倍、3倍する関数を作成
double = create_multiplier(2)
triple = create_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
3. クロージャの活用
def create_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
# カウンターを作成
counter1 = create_counter()
counter2 = create_counter()
print(counter1()) # 1
print(counter1()) # 2
print(counter2()) # 1(独立したカウンター)
デコレータ(高階関数の応用)
1. 基本的なデコレータ
def timer_decorator(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__}の実行時間: {end - start:.4f}秒")
return result
return wrapper
@timer_decorator
def slow_function():
import time
time.sleep(1)
return "完了"
slow_function() # 実行時間が表示される
2. 引数を持つデコレータ
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("太郎") # 3回実行される
実践的な高階関数の応用
1. データ処理パイプライン
def pipeline(*functions):
def apply(data):
for func in functions:
data = func(data)
return data
return apply
# データ処理関数
def add_one(x): return x + 1
def multiply_by_two(x): return x * 2
def square(x): return x ** 2
# パイプラインを作成
process = pipeline(add_one, multiply_by_two, square)
result = process(3) # (3+1)*2の2乗 = 64
print(result) # 64
2. 条件付きフィルタリング
def create_filter(condition):
return lambda items: [item for item in items if condition(item)]
# 条件を定義
is_positive = lambda x: x > 0
is_even = lambda x: x % 2 == 0
numbers = [-2, -1, 0, 1, 2, 3, 4, 5]
# フィルターを作成
positive_filter = create_filter(is_positive)
even_filter = create_filter(is_even)
print(positive_filter(numbers)) # [1, 2, 3, 4, 5]
print(even_filter(numbers)) # [-2, 0, 2, 4]
3. 関数の合成
def compose(f, g):
return lambda x: f(g(x))
def add_five(x):
return x + 5
def multiply_by_three(x):
return x * 3
# 関数を合成
composed = compose(add_five, multiply_by_three)
result = composed(2) # (2 * 3) + 5 = 11
print(result) # 11
関数型プログラミングのテクニック
1. 部分適用(Partial Application)
from functools import partial
def multiply(x, y):
return x * y
# 部分適用で特定の倍数関数を作成
double = partial(multiply, 2)
triple = partial(multiply, 3)
print(double(5)) # 10
print(triple(5)) # 15
2. カリー化(Currying)
def curry_add(x):
def add_y(y):
def add_z(z):
return x + y + z
return add_z
return add_y
# カリー化された関数の使用
add_1 = curry_add(1)
add_1_2 = add_1(2)
result = add_1_2(3) # 1 + 2 + 3 = 6
print(result) # 6
# 一行で実行
result2 = curry_add(10)(20)(30) # 60
print(result2) # 60
3. メモ化(Memoization)
def memoize(func):
cache = {}
def wrapper(*args):
if args in cache:
return cache[args]
result = func(*args)
cache[args] = result
return result
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 高速計算
実用的な高階関数パターン
1. バリデーター関数
def create_validator(*validators):
def validate(value):
return all(validator(value) for validator in validators)
return validate
# 個別のバリデーター
def min_length(length):
return lambda s: len(s) >= length
def contains_digit():
return lambda s: any(c.isdigit() for c in s)
# 複合バリデーター
password_validator = create_validator(
min_length(8),
contains_digit()
)
print(password_validator("password123")) # True
print(password_validator("short")) # False
2. イベントハンドラー
class EventManager:
def __init__(self):
self.handlers = []
def add_handler(self, handler):
self.handlers.append(handler)
def trigger(self, event):
for handler in self.handlers:
handler(event)
# イベントハンドラーを定義
def log_handler(event):
print(f"ログ: {event}")
def email_handler(event):
print(f"メール送信: {event}")
# 使用例
manager = EventManager()
manager.add_handler(log_handler)
manager.add_handler(email_handler)
manager.trigger("ユーザー登録")
3. 設定可能な処理
def process_data(data, processors):
for processor in processors:
data = processor(data)
return data
# 処理関数
def normalize(data):
return [x.strip().lower() for x in data]
def remove_empty(data):
return [x for x in data if x]
def add_prefix(prefix):
return lambda data: [f"{prefix}{x}" for x in data]
# データ処理
raw_data = [" Hello ", "WORLD", "", "Python "]
processors = [normalize, remove_empty, add_prefix(">>> ")]
result = process_data(raw_data, processors)
print(result) # ['>>> hello', '>>> world', '>>> python']
パフォーマンス最適化
1. ジェネレータとの組み合わせ
def filter_map(filter_func, map_func, iterable):
for item in iterable:
if filter_func(item):
yield map_func(item)
# 大きなデータセットの効率的な処理
numbers = range(1000000)
result = filter_map(
lambda x: x % 2 == 0, # 偶数のみ
lambda x: x ** 2, # 2乗
numbers
)
# 最初の5つだけ取得(メモリ効率的)
first_five = list(itertools.islice(result, 5))
print(first_five) # [0, 4, 16, 36, 64]
2. 遅延評価
def lazy_operation(func):
def wrapper(*args, **kwargs):
def execute():
return func(*args, **kwargs)
return execute
return wrapper
@lazy_operation
def expensive_calculation(n):
return sum(i**2 for i in range(n))
# 関数は実行されない(遅延評価)
lazy_calc = expensive_calculation(10000)
# 必要な時に実行
result = lazy_calc()
print(result)
よくある間違いと対策
1. クロージャでの変数参照
# 間違い:すべて同じ値を参照
functions = []
for i in range(3):
functions.append(lambda: i) # すべて2を返す
# 正しい:デフォルト引数で値を固定
functions = []
for i in range(3):
functions.append(lambda x=i: x)
for func in functions:
print(func()) # 0, 1, 2
2. 副作用のある関数
# 避けるべき:副作用のある高階関数
def bad_map(func, lst):
for i in range(len(lst)):
lst[i] = func(lst[i]) # 元のリストを変更
return lst
# 推奨:純粋関数
def good_map(func, lst):
return [func(x) for x in lst] # 新しいリストを返す
まとめ
Python高階関数をマスターすることで、より洗練されたコードが書けるようになります。map、filter、reduceなどの基本的な高階関数から、デコレータ、クロージャ、関数合成まで、幅広いテクニックを活用することで、コードの再利用性と可読性が大幅に向上します。
特に重要なのは、関数型プログラミングの思考法を身につけることです。副作用を避け、純粋関数を意識することで、バグの少ない保守しやすいコードが作成できます。
実際のプロジェクトでは、適切な場面で高階関数を使い分け、過度に複雑にならないよう注意しながら、Pythonの強力な機能を最大限に活用してください。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座