閉じる

Pythonのラムダ式とは?map/filter/sortedで使う実例集

Pythonのラムダ式は、関数に名前を付けずにその場で小さな処理を書きたい時に便利です。

特にmapやfilter、sortedのkey引数と組み合わせると、読みやすく短いコードが書けます。

本記事では、ラムダ式の基本から実例、落とし穴の回避方法まで、初心者の方にも段階的にわかるように解説します。

Pythonのラムダ式(lambda)の基本

ラムダ式とは?匿名関数の役割

ラムダ式は、関数に名前を付けずに定義するための簡潔な構文です。

主にmapfiltersortedkey引数のように、短い関数を一時的に渡す場面で使います。

関数の再利用が不要で、式(1行)で書ける場合に有効です。

構文(lambda 引数: 式)と書き方

ラムダ式の基本構文はlambda 引数: 式です。

式が評価された値が戻り値になります。

Python
# 基本: 引数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の方が適します。

以下に違いを整理します。

項目lambdadef
名前なし(代入で名前を付けることも可能)必須
本体1つの式のみ複数の文や複雑な処理が可能
アノテーションパラメータ単位で直接は不可可能(引数・戻り値とも)
docstringないあり
デバッグ時の表示<lambda>と表示される関数名で表示される
ユースケース短い一時的な関数再利用・説明責任のある関数

迷ったらdefを使い、短い一時利用だけラムダ式が基本指針です。

制限事項: 文は不可・1式のみ

ラムダ式の本体は式1つだけで、代入文・for文・if文ブロックなどの「文」は書けません

条件は条件式 if 条件 else 別結果のような式で表現します。

Python
# 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)」に特に注意が必要です。

Python
# 期待: 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や型エイリアスを使います。

Python
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

よくある落とし穴(初心者向け)

  • 長い処理をラムダ式で無理に書くと可読性が落ちます。defにしましょう。
  • map/filterの併用でネストが深くなると読みにくくなります。内包表記で置き換えを検討します。
  • ループ変数の遅延束縛はi=iのデフォルト引数で防ぎます。
  • 例外処理やロギングなど文が必要なら、ラムダ式ではなくdefを使います。

Pythonのmapで使う(lambdaで一括変換)

基本: リストを変換する例

mapは各要素に関数を適用するイテレータを返します。

以下は数値の2乗です。

Python
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は複数のイテラブルを受け取り、最短の長さまで適用します。

Python
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はイテレータです。

一度消費すると再利用できません

Python
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が真となる要素だけを返します。

Python
nums = list(range(10))
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)
実行結果
[0, 2, 4, 6, 8]

複数条件の書き方

論理演算子andorで条件を組み合わせます。

Python
nums = list(range(20))
# 5の倍数かつ10未満
picked = list(filter(lambda x: (x % 5 == 0) and (x < 10), nums))
print(picked)
実行結果
[0, 5]

文字列・辞書データの抽出

文字列のパターンや辞書のキーに基づく抽出も簡単です。

Python
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']

可読性とパフォーマンスの注意

複雑な条件は内包表記の[x for x in xs if 条件]の方が読みやすいことが多いです。

巨大データで遅延評価が必要なら、filter(x for x in xs if 条件)のジェネレータ式を選びます。

Pythonのsortedで使う(lambdaでカスタムソート)

key引数の基本と使い方

sorted(iterable, key=関数)は、各要素にkey関数を適用した結果で並べ替えます。

元データは変更されず、新しいリストを返します。

Python
names = ["bob", "Alice", "carol"]
# 大文字小文字を無視してソート
sorted_names = sorted(names, key=lambda s: s.lower())
print(sorted_names)
実行結果
['Alice', 'bob', 'carol']

辞書リストをキーで並べ替え

実務でよくある「辞書のリスト」を特定キーで並べ替えます。

Python
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キー…の順に比較されます。

Python
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を重ねる)も可能です。

Python
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使用例

minmaxlist.sortでもkeyが使えます。

Python
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)]

まとめ

ラムダ式は、短い処理をその場で定義できる匿名関数で、mapfiltersortedkeyと組み合わせるとコードを簡潔にできます。

ただし本体は1つの式のみループ変数の遅延束縛などの注意点があるため、長い処理や例外処理が必要な場合はdefに切り替えましょう。

型ヒントはCallableや型エイリアスで補助できます。

Python 実践TIPS - コーディング効率化・Pythonic
この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!