Pythonのラムダ式は、関数に名前を付けずにその場で小さな処理を書きたい時に便利です。
特にmapやfilter、sortedのkey
引数と組み合わせると、読みやすく短いコードが書けます。
本記事では、ラムダ式の基本から実例、落とし穴の回避方法まで、初心者の方にも段階的にわかるように解説します。
Pythonのラムダ式(lambda)の基本
ラムダ式とは?匿名関数の役割
ラムダ式は、関数に名前を付けずに定義するための簡潔な構文です。
主にmap
やfilter
、sorted
のkey
引数のように、短い関数を一時的に渡す場面で使います。
関数の再利用が不要で、式(1行)で書ける場合に有効です。
構文(lambda 引数: 式)と書き方
ラムダ式の基本構文はlambda 引数: 式
です。
式が評価された値が戻り値になります。
# 基本: 引数xを2倍にする匿名関数
double = lambda x: x * 2
print(double(5)) # 10
# 引数を複数取る例
add = lambda a, b: a + b
print(add(3, 4)) # 7
# すぐに呼び出す(即時実行)
result = (lambda s: s.upper())("hello")
print(result) # "HELLO"
# mapと組み合わせる
nums = [1, 2, 3]
squared = list(map(lambda n: n * n, nums)) # [1, 4, 9]
print(squared)
10
7
HELLO
[1, 4, 9]
defとの違いと使い分け
ラムダ式は「短い式」限定、def
は「本格的な関数」です。
ドキュメンテーションやデバッグ、再利用性を考えるとdef
の方が適します。
以下に違いを整理します。
項目 | lambda | def |
---|---|---|
名前 | なし(代入で名前を付けることも可能) | 必須 |
本体 | 1つの式のみ | 複数の文や複雑な処理が可能 |
アノテーション | パラメータ単位で直接は不可 | 可能(引数・戻り値とも) |
docstring | ない | あり |
デバッグ時の表示 | <lambda> と表示される | 関数名で表示される |
ユースケース | 短い一時的な関数 | 再利用・説明責任のある関数 |
迷ったらdef
を使い、短い一時利用だけラムダ式が基本指針です。
制限事項: 文は不可・1式のみ
ラムダ式の本体は式1つだけで、代入文・for文・if文ブロックなどの「文」は書けません。
条件は条件式 if 条件 else 別結果
のような式で表現します。
# OK: 条件演算子は「式」
label = lambda x: "even" if x % 2 == 0 else "odd"
print(label(3)) # "odd"
# NG例(コメントのみ、実際に実行するとSyntaxError):
# bad = lambda x: y = x + 1 # 代入文は不可
# bad2 = lambda x: for i in range(x): print(i) # 文は不可
# 代わりにdefで書く
def verbose(x):
y = x + 1
print(y)
return y
odd
スコープとクロージャの注意点
ラムダ式も通常の関数と同じスコープ・クロージャを持ちます。
ループ変数の「遅延束縛(late binding)」に特に注意が必要です。
# 期待: 0,1,2 と表示したい
funcs_bad = [lambda: i for i in range(3)]
print([f() for f in funcs_bad]) # すべて最後のi=2を参照してしまう -> [2, 2, 2]
# 回避1: デフォルト引数で値を束縛
funcs_ok1 = [lambda i=i: i for i in range(3)]
print([f() for f in funcs_ok1]) # [0, 1, 2]
# 回避2: 引数を取る関数にして即時呼び出し
funcs_ok2 = [(lambda x: (lambda: x))(i) for i in range(3)]
print([f() for f in funcs_ok2]) # [0, 1, 2]
[2, 2, 2]
[0, 1, 2]
[0, 1, 2]
型ヒントの付け方の限界
ラムダ式は引数や戻り値に直接型注釈を付けられません。
代わりにtyping.Callable
や型エイリアスを使います。
from typing import Callable, TypeAlias
# 関数の受け渡し側でCallableを使う
def apply(f: Callable[[int], int], x: int) -> int:
return f(x)
# ラムダに直接注釈は付けられないが、受け手で担保できる
print(apply(lambda n: n + 1, 10)) # 11
# 型エイリアスで表現する
IntToInt: TypeAlias = Callable[[int], int]
inc: IntToInt = lambda n: n + 1
print(inc(5))
11
6
- typing.Callable / TypeAlias
- typing.TypeAlias — Python 3.13.7 ドキュメント
- 関連記事:型ヒントの書き方と使い方: typingとmypyまで
よくある落とし穴(初心者向け)
- 長い処理をラムダ式で無理に書くと可読性が落ちます。
def
にしましょう。 - map/filterの併用でネストが深くなると読みにくくなります。内包表記で置き換えを検討します。
- ループ変数の遅延束縛は
i=i
のデフォルト引数で防ぎます。 - 例外処理やロギングなど文が必要なら、ラムダ式ではなく
def
を使います。
Pythonのmapで使う(lambdaで一括変換)
基本: リストを変換する例
mapは各要素に関数を適用するイテレータを返します。
以下は数値の2乗です。
nums = [1, 2, 3, 4]
squared_iter = map(lambda x: x * x, nums) # まだイテレータ
squared_list = list(squared_iter) # list化して使う
print(squared_list)
[1, 4, 9, 16]
参考として、同じ処理は[x*x for x in nums]
でも書けます。
初心者には内包表記の方が読みやすい場合があります。
複数イテラブルを同時に変換
map
は複数のイテラブルを受け取り、最短の長さまで適用します。
a = [1, 2, 3]
b = [10, 20, 30, 40]
summed = list(map(lambda x, y: x + y, a, b)) # 3要素で止まる
print(summed)
[11, 22, 33]
出力の扱い(イテレータ・list化)
Python 3のmap
はイテレータです。
一度消費すると再利用できません。
nums = [1, 2, 3]
m = map(lambda x: x * 2, nums)
print(list(m)) # ここで消費される
print(list(m)) # もう空
[2, 4, 6]
[]
必要に応じてlist()
で一度だけ展開するか、最初から内包表記を使います。
よくあるミスと対処
- 出力の未list化: 表示や再利用の前に
list()
が必要です。 - 複雑な変換をラムダに詰め込む: 可読性低下。
def
か関数を別定義しましょう。 - 複数イテラブルの長さ不一致: 余剰要素は無視されます。必要なら
itertools.zip_longest
を検討します。
Pythonのfilterで使う(lambdaで条件抽出)
基本: 条件で要素を抽出する例
filter(func, iterable)
はfuncが真となる要素だけを返します。
nums = list(range(10))
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)
[0, 2, 4, 6, 8]
複数条件の書き方
論理演算子and
やor
で条件を組み合わせます。
nums = list(range(20))
# 5の倍数かつ10未満
picked = list(filter(lambda x: (x % 5 == 0) and (x < 10), nums))
print(picked)
[0, 5]
文字列・辞書データの抽出
文字列のパターンや辞書のキーに基づく抽出も簡単です。
words = ["apple", "Banana", "apricot", "berry"]
# 先頭がa(大文字小文字無視)
starts_with_a = list(filter(lambda w: w.lower().startswith("a"), words))
print(starts_with_a)
users = [
{"name": "Alice", "age": 19},
{"name": "Bob", "age": 25},
{"name": "Carol", "age": 17},
]
# 20歳以上のユーザーだけ
adults = list(filter(lambda u: u["age"] >= 20, users))
print([u["name"] for u in adults])
['apple', 'apricot']
['Bob']
- 関連記事:辞書(dict)とは?キーと値で管理する基本 / 辞書操作まとめ
可読性とパフォーマンスの注意
複雑な条件は内包表記の[x for x in xs if 条件]
の方が読みやすいことが多いです。
巨大データで遅延評価が必要なら、filter
か(x for x in xs if 条件)
のジェネレータ式を選びます。
Pythonのsortedで使う(lambdaでカスタムソート)
key引数の基本と使い方
sorted(iterable, key=関数)
は、各要素にkey関数を適用した結果で並べ替えます。
元データは変更されず、新しいリストを返します。
names = ["bob", "Alice", "carol"]
# 大文字小文字を無視してソート
sorted_names = sorted(names, key=lambda s: s.lower())
print(sorted_names)
['Alice', 'bob', 'carol']
辞書リストをキーで並べ替え
実務でよくある「辞書のリスト」を特定キーで並べ替えます。
people = [
{"name": "Bob", "age": 25},
{"name": "Alice", "age": 20},
{"name": "Carol", "age": 25},
]
by_age = sorted(people, key=lambda p: p["age"])
print([(p["name"], p["age"]) for p in by_age])
[('Alice', 20), ('Bob', 25), ('Carol', 25)]
複数キーでソート(tupleキー)
複数のキーはタプルを返すことで対応できます。
第1キーで比較し、同値なら第2キー…の順に比較されます。
people = [
{"name": "Bob", "age": 25},
{"name": "Alice", "age": 25},
{"name": "Carol", "age": 20},
]
# 年齢(昇順) → 名前(昇順)
sorted_people = sorted(people, key=lambda p: (p["age"], p["name"]))
print([(p["name"], p["age"]) for p in sorted_people])
[('Carol', 20), ('Alice', 25), ('Bob', 25)]
逆順(reverse)と安定ソート
reverse=True
で全体を逆順にできます。
Pythonのソートは安定ソートなので、複数段ソート(後ろのキーから順にlist.sort
を重ねる)も可能です。
records = [
("A", 2),
("B", 1),
("C", 2),
("D", 1),
]
# 2段階: まず第2要素で昇順、次にレーベルを降順(安定性により同順位の中だけ反映)
tmp = sorted(records, key=lambda r: r[1]) # 第2要素昇順
final = sorted(tmp, key=lambda r: r[0], reverse=True) # ラベル降順
print(final)
# 1回でやるならtupleキー + reverseの工夫
once = sorted(records, key=lambda r: (-r[1], r[0])) # 第2要素を負にして実質降順
print(once)
[('C', 2), ('A', 2), ('D', 1), ('B', 1)]
[('C', 2), ('A', 2), ('D', 1), ('B', 1)]
関連API: min/max/list.sortのkey使用例
min
やmax
、list.sort
でもkey
が使えます。
words = ["aaa", "b", "cc"]
shortest = min(words, key=lambda w: len(w))
longest = max(words, key=lambda w: len(w))
print(shortest, longest)
data = [("alice", 3), ("bob", 1), ("carol", 2)]
data.sort(key=lambda t: t[1]) # インプレースで並べ替え
print(data)
b aaa
[('bob', 1), ('carol', 2), ('alice', 3)]
- min / max — 組み込み関数
- max() – 組み込み関数 — Python 3.13.7 ドキュメント
- 関連記事:リストを逆順ソート/反転する3つの方法
- 関連記事:辞書でキー存在をチェックする3つの書き方
まとめ
ラムダ式は、短い処理をその場で定義できる匿名関数で、map
やfilter
、sorted
のkey
と組み合わせるとコードを簡潔にできます。
ただし本体は1つの式のみ、ループ変数の遅延束縛などの注意点があるため、長い処理や例外処理が必要な場合はdef
に切り替えましょう。
型ヒントはCallable
や型エイリアスで補助できます。