Python関数型プログラミング入門 – map・filter・reduceから始める実践ガイド
関数型プログラミングとは?基本概念を5分で理解
**関数型プログラミング(Functional Programming)**は、関数を中心としたプログラミングパラダイムです。データの変更(副作用)を避け、関数の組み合わせで問題を解決します。
オブジェクト指向との違い
| 手法 | 考え方 | 特徴 |
|---|---|---|
| オブジェクト指向 | データ + メソッド | 状態を変更する |
| 関数型 | 関数 + データ | 新しい値を生成する |
# オブジェクト指向的
class Calculator:
def __init__(self):
self.result = 0
def add(self, x):
self.result += x
# 関数型的
def add(x, y):
return x + y
Python関数型プログラミングの基本関数
1. map関数 – データの変換
# 全ての要素を2倍にする
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, 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]
3. reduce関数 – データの集約
from functools import reduce
# 全ての要素の合計を計算
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x + y, numbers)
print(total) # 15
lambda式(無名関数)の活用
基本的な使い方
# 通常の関数定義
def square(x):
return x ** 2
# lambda式で同じ処理
square = lambda x: x ** 2
print(square(5)) # 25
実践的な活用例
# 辞書のソート
students = [{"name": "太郎", "score": 85}, {"name": "花子", "score": 92}]
sorted_students = sorted(students, key=lambda x: x["score"])
print(sorted_students) # スコア順でソート
高階関数の実装
関数を返す関数
def multiplier(n):
return lambda x: x * n
double = multiplier(2)
triple = multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
関数を引数に取る関数
def apply_operation(numbers, operation):
return [operation(x) for x in numbers]
numbers = [1, 2, 3, 4, 5]
squared = apply_operation(numbers, lambda x: x**2)
print(squared) # [1, 4, 9, 16, 25]
デコレータを使った関数型アプローチ
基本的なデコレータ
def timing_decorator(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"実行時間: {time.time() - start:.4f}秒")
return result
return wrapper
@timing_decorator
def slow_function():
import time
time.sleep(1)
return "完了"
純粋関数(Pure Function)の実践
純粋関数の特徴
# ✅ 純粋関数:同じ入力で同じ出力、副作用なし
def add(x, y):
return x + y
# ❌ 非純粋関数:外部状態に依存
global_var = 10
def impure_add(x):
return x + global_var
副作用を避ける方法
# ❌ 元のリストを変更
def bad_double(numbers):
for i in range(len(numbers)):
numbers[i] *= 2
return numbers
# ✅ 新しいリストを作成
def good_double(numbers):
return [x * 2 for x in numbers]
実践的な関数型パターン
1. パイプライン処理
from functools import reduce
def pipe(*functions):
return lambda x: reduce(lambda acc, f: f(acc), functions, x)
# 数値を2倍して、3を足して、文字列化
pipeline = pipe(
lambda x: x * 2,
lambda x: x + 3,
str
)
result = pipeline(5) # "13"
2. カリー化(Currying)
def curry_add(x):
return lambda y: lambda z: x + y + z
add_5 = curry_add(5)
add_5_and_3 = add_5(3)
result = add_5_and_3(2) # 10
3. 部分適用
from functools import partial
def multiply(x, y, z):
return x * y * z
# yを2に固定した関数を作成
double_multiply = partial(multiply, y=2)
result = double_multiply(3, 4) # 24
関数型 vs 命令型の比較
データ処理の例
# 命令型スタイル
def process_data_imperative(data):
result = []
for item in data:
if item > 0:
result.append(item * 2)
return result
# 関数型スタイル
def process_data_functional(data):
return list(map(lambda x: x * 2, filter(lambda x: x > 0, data)))
# さらに読みやすく
def process_data_readable(data):
positive = filter(lambda x: x > 0, data)
doubled = map(lambda x: x * 2, positive)
return list(doubled)
イミュータブル(不変)データの活用
namedtupleの使用
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p1 = Point(1, 2)
p2 = p1._replace(x=3) # 新しいインスタンスを作成
print(p1) # Point(x=1, y=2)
print(p2) # Point(x=3, y=2)
dataclassesでイミュータブルクラス
from dataclasses import dataclass
@dataclass(frozen=True)
class ImmutableUser:
name: str
age: int
user = ImmutableUser("太郎", 25)
# user.age = 26 # エラー:変更不可
パフォーマンスと最適化
ジェネレータとの組み合わせ
# メモリ効率的な処理
def process_large_data(data):
filtered = filter(lambda x: x > 100, data)
doubled = map(lambda x: x * 2, filtered)
return doubled # ジェネレータを返す
# 必要な時だけ計算される
large_numbers = range(1000000)
processed = process_large_data(large_numbers)
first_10 = list(itertools.islice(processed, 10))
よくある間違いと対処法
1. lambda式の過度な使用
# ❌ 読みにくい
result = list(filter(lambda x: x['score'] > 80 and x['age'] < 30, students))
# ✅ 読みやすい
def is_young_high_scorer(student):
return student['score'] > 80 and student['age'] < 30
result = list(filter(is_young_high_scorer, students))
2. 副作用の混入
# ❌ 副作用あり
def bad_process(items, results):
for item in items:
results.append(item * 2) # 外部状態を変更
# ✅ 純粋関数
def good_process(items):
return [item * 2 for item in items]
実務での活用例
1. データ変換パイプライン
# JSONデータの処理
users = [{"name": "太郎", "age": 25}, {"name": "花子", "age": 30}]
adult_names = list(map(
lambda user: user["name"],
filter(lambda user: user["age"] >= 20, users)
))
2. 設定値の適用
# 設定を関数として管理
def create_processor(config):
return lambda data: data * config["multiplier"] + config["offset"]
config = {"multiplier": 2, "offset": 10}
processor = create_processor(config)
result = processor(5) # 20
3. バリデーション処理
def validate_all(*validators):
return lambda data: all(validator(data) for validator in validators)
is_valid_user = validate_all(
lambda user: len(user.get("name", "")) > 0,
lambda user: user.get("age", 0) > 0,
lambda user: "@" in user.get("email", "")
)
まとめ:関数型プログラミングの利点
メリット
- コードの再利用性が高い
- テストが容易
- 並列処理に適している
- バグが発生しにくい
適用場面
- データ変換処理
- 設定値の管理
- フィルタリング・集計処理
- パイプライン処理
関数型プログラミングをマスターすることで、より保守性が高く、理解しやすいPythonコードが書けるようになります。まずはmap、filter、reduceから始めて、徐々に高階関数やイミュータブルデータの概念を取り入れていきましょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座



