Skip to content
トピック
Python
Python Lambda関数:実用的な例を用いた明快ガイド

Python Lambda関数:実用的な例を用いた明快ガイド

Updated on

すべてのPythonプロジェクトには、小さなヘルパー関数が蓄積されていきます。数値を2倍にする関数。空白を除去する関数。辞書から名字を抽出する関数。それぞれ2〜3行で、1回だけ使われ、二度と覚えることのない名前でモジュールを散らかします。Python Lambda関数は、必要な場所にそのまま小さな使い捨て関数を定義できるようにすることで、この問題を解決します -- def不要、名前不要、縦方向のスペースの無駄もありません。

📚

このガイドでは、Python Lambda関数について知っておくべきすべてをカバーします:構文、組み合わせて使う組み込み関数、実際のコードでの実用的なパターン、そして避けるべき具体的な状況について。

Lambda関数とは?

Lambda関数は、匿名の単一式関数です。「匿名」とは名前がないことを意味します。「単一式」とは、関数本体が正確に1つの式であり、その結果が自動的に返されることを意味します。Pythonはその式を評価し、結果を返します -- return文は不要です。

この用語はラムダ計算(数理論理学の形式体系)に由来しています。しかし、数学を理解する必要はありません。実用的なPythonでは、ラムダは単に小さな関数を書くための短い方法です。

以下は通常の関数とそのLambda等価物です:

# Regular function
def double(x):
    return x * 2
 
print(double(5))
# 10
 
# Lambda equivalent
double_lambda = lambda x: x * 2
 
print(double_lambda(5))
# 10

どちらも同じ結果を生成します。Lambda版は1行に収まり、defreturnの形式を省略します。

Lambda構文

Python Lambdaの構文は以下の通りです:

lambda arguments: expression
  • lambda -- 匿名関数を示すキーワード。
  • arguments -- カンマで区切られた0個以上のパラメータ。括弧は不要。
  • expression -- 評価されて返される単一の式。文は使えません(ifブロック、forループ、=での代入は不可)。

範囲を示すいくつかの簡単な例:

# No arguments
greet = lambda: "Hello, world!"
print(greet())
# Hello, world!
 
# One argument
square = lambda x: x ** 2
print(square(9))
# 81
 
# Two arguments
add = lambda a, b: a + b
print(add(3, 7))
# 10
 
# Default argument
power = lambda base, exp=2: base ** exp
print(power(3))
# 9
print(power(3, 3))
# 27

重要な制約は、本体が単一の式でなければならないことです。複数行のロジックを書いたり、if文を使ったり(ただし条件式は使用可能)、代入を含めたりすることはできません。これは意図的なものです -- ラムダはシンプルな操作のために設計されています。

Lambdaとmap() -- リストの変換

map()はイテラブルの各要素に関数を適用し、イテレータを返します。変換は多くの場合1行で表現できるほど単純なため、Lambda関数はmap()の自然なパートナーです。

numbers = [1, 2, 3, 4, 5]
 
# Square each number
squared = list(map(lambda x: x ** 2, numbers))
print(squared)
# [1, 4, 9, 16, 25]
 
# Convert temperatures from Celsius to Fahrenheit
celsius = [0, 20, 37, 100]
fahrenheit = list(map(lambda c: round(c * 9/5 + 32, 1), celsius))
print(fahrenheit)
# [32.0, 68.0, 98.6, 212.0]
 
# Extract first names from full names
names = ["Ada Lovelace", "Grace Hopper", "Alan Turing"]
first_names = list(map(lambda name: name.split()[0], names))
print(first_names)
# ['Ada', 'Grace', 'Alan']

map()とラムダの組み合わせは、マッピングロジックが単純な1ステップの変換である場合、リスト内包表記のクリーンな代替手段です。より複雑な変換の場合、リスト内包表記の方が読みやすい傾向があります。

Lambdaとfilter() -- 要素のフィルタリング

filter()は関数とイテラブルを受け取り、関数がTrueを返す要素のみを生成するイテレータを返します。Lambda関数を使うと、述語をインラインで簡単に定義できます。

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 
# Keep only even numbers
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)
# [2, 4, 6, 8, 10]
 
# Keep strings longer than 4 characters
words = ["cat", "elephant", "dog", "butterfly", "ant"]
long_words = list(filter(lambda w: len(w) > 4, words))
print(long_words)
# ['elephant', 'butterfly']
 
# Filter out None values
data = [1, None, 3, None, 5, None, 7]
clean = list(filter(lambda x: x is not None, data))
print(clean)
# [1, 3, 5, 7]

map()と同様に、filter() + ラムダの組み合わせは単純な条件に最適です。フィルタリングロジックに複数のチェックが含まれる場合は、リスト内包表記や名前付き関数の方が通常明確です。

Lambdaとsorted()およびsort() -- カスタムソートキー

ソートはLambda関数の最も一般的で実用的な用途の1つです。sorted()関数と.sort()メソッドはどちらもkeyパラメータを受け付けます -- 各要素から比較値を抽出する関数です。

# Sort strings by length
fruits = ["banana", "kiwi", "strawberry", "fig", "apple"]
by_length = sorted(fruits, key=lambda s: len(s))
print(by_length)
# ['fig', 'kiwi', 'apple', 'banana', 'strawberry']
 
# Sort tuples by the second element
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
by_second = sorted(pairs, key=lambda pair: pair[1])
print(by_second)
# [(3, 'a'), (1, 'b'), (2, 'c')]
 
# Sort dictionaries by a specific key
students = [
    {"name": "Alice", "grade": 88},
    {"name": "Bob", "grade": 95},
    {"name": "Charlie", "grade": 72},
]
by_grade = sorted(students, key=lambda s: s["grade"], reverse=True)
for s in by_grade:
    print(f"{s['name']}: {s['grade']}")
# Bob: 95
# Alice: 88
# Charlie: 72

ラムダを使ったソートは非常に広く使われており、Pythonの慣用的なパターンになっています。特定の属性やフィールドで複雑なオブジェクトをソートする必要がある場合、ラムダキー関数が標準的なアプローチです。

複数の基準でのソート

ラムダからタプルを返すことで、複数のフィールドでソートできます:

employees = [
    {"name": "Alice", "dept": "Engineering", "salary": 95000},
    {"name": "Bob", "dept": "Marketing", "salary": 72000},
    {"name": "Charlie", "dept": "Engineering", "salary": 88000},
    {"name": "Diana", "dept": "Marketing", "salary": 85000},
]
 
# Sort by department (ascending), then by salary (descending)
sorted_emp = sorted(employees, key=lambda e: (e["dept"], -e["salary"]))
for e in sorted_emp:
    print(f"{e['dept']:12s} {e['name']:8s} ${e['salary']:,}")
# Engineering  Alice    $95,000
# Engineering  Charlie  $88,000
# Marketing    Diana    $85,000
# Marketing    Bob      $72,000

Lambdaとfunctoolsのreduce()

functools.reduce()は2引数の関数をイテラブルの要素に累積的に適用し、単一の値に縮約します。Lambda関数はreduce()と自然に組み合わせて、簡潔な集約を行えます。

from functools import reduce
 
numbers = [1, 2, 3, 4, 5]
 
# Product of all numbers
product = reduce(lambda x, y: x * y, numbers)
print(product)
# 120
 
# Find the maximum value (for demonstration; use max() in practice)
largest = reduce(lambda a, b: a if a > b else b, numbers)
print(largest)
# 5
 
# Concatenate a list of strings
words = ["Python", " ", "lambda", " ", "functions"]
sentence = reduce(lambda a, b: a + b, words)
print(sentence)
# Python lambda functions
 
# Flatten a list of lists
nested = [[1, 2], [3, 4], [5, 6]]
flat = reduce(lambda acc, lst: acc + lst, nested)
print(flat)
# [1, 2, 3, 4, 5, 6]

注意点:reduce()は意図を不明瞭にすることがあります。合計のような一般的な操作にはsum()を使用してください。最小値/最大値にはmin()max()を使用してください。組み込み関数が存在しないカスタム集約のために、reduce()とラムダを使用してください。

Lambda vs def -- それぞれの使い分け

これが実践で最も重要な質問です。Lambdaとdefはどちらも関数オブジェクトを作成しますが、異なる目的を持っています。

特徴lambdadef
名前匿名(名前なし)名前付き関数
本体単一式のみ複数の文、ループ、条件
戻り値暗黙的(式の結果)明示的なreturn
Docstring非対応対応
型ヒント非対応対応
デバッグトレースバックに<lambda>と表示トレースバックに関数名を表示
可読性シンプルで短い操作に最適複数ステップのものに最適
テスト容易性単独でのテストが困難名前でのユニットテストが容易
再利用通常、単回使用、インライン再利用のために設計
デコレータ@decorator構文使用不可完全なデコレータサポート

Lambdaを使うべき場合

  • ソートキー: sorted(items, key=lambda x: x.name)
  • 素早いmap/filter操作: map(lambda x: x.strip(), lines)
  • コールバック引数: 呼び出し可能なパラメータを受け付ける関数
  • シンプルな辞書またはタプルアクセス: key=lambda item: item[1]

defを使うべき場合

  • 関数に複数の式がある場合
  • docstringや型ヒントが必要な場合
  • 関数が複数の場所から呼び出される場合
  • ロジックにエラー処理や分岐が必要な場合
  • デバッグのためにスタックトレースに意味のある名前が必要な場合

経験則: ラムダが1行に快適に収まらない場合、または何をしているか理解するために2度読む必要がある場合は、代わりにdefを使用してください。

複数の引数を持つLambda

Lambda関数は、*args**kwargsを含む任意の数の引数を受け付けることができます:

# Three arguments
volume = lambda l, w, h: l * w * h
print(volume(3, 4, 5))
# 60
 
# Using *args for variable arguments
sum_all = lambda *args: sum(args)
print(sum_all(1, 2, 3, 4, 5))
# 15
 
# Using **kwargs
build_greeting = lambda **kwargs: f"Hello, {kwargs.get('name', 'stranger')}!"
print(build_greeting(name="Alice"))
# Hello, Alice!
print(build_greeting())
# Hello, stranger!
 
# Conditional expression inside lambda
classify = lambda x: "positive" if x > 0 else ("zero" if x == 0 else "negative")
print(classify(5))
# positive
print(classify(0))
# zero
print(classify(-3))
# negative

最後の例の条件式(a if condition else b)に注目してください。これがラムダ内に分岐ロジックを追加する唯一の方法です。機能しますが、複数の条件をネストすると可読性が急速に低下します。

辞書操作でのLambda

Lambda関数は辞書データの変換とソートに便利です:

# Sort a dictionary by value
scores = {"Alice": 88, "Bob": 95, "Charlie": 72, "Diana": 91}
sorted_scores = dict(sorted(scores.items(), key=lambda item: item[1], reverse=True))
print(sorted_scores)
# {'Bob': 95, 'Diana': 91, 'Alice': 88, 'Charlie': 72}
 
# Apply a transformation to all dictionary values
prices = {"apple": 1.20, "banana": 0.50, "cherry": 2.00}
discounted = {k: round(v * 0.9, 2) for k, v in prices.items()}
print(discounted)
# {'apple': 1.08, 'banana': 0.45, 'cherry': 1.8}
 
# Group items using a lambda as a key function
from itertools import groupby
 
data = ["apple", "avocado", "banana", "blueberry", "cherry", "cranberry"]
data_sorted = sorted(data, key=lambda x: x[0])
 
for letter, group in groupby(data_sorted, key=lambda x: x[0]):
    print(f"{letter}: {list(group)}")
# a: ['apple', 'avocado']
# b: ['banana', 'blueberry']
# c: ['cherry', 'cranberry']

LambdaとPandas:df.apply()とdf.sort_values()

Lambda関数はpandasで行レベルの変換やカスタムソートに多用されています。apply()メソッドはDataFrameの各行または列に関数を実行し、ラムダはコードをインラインに保ちます。

import pandas as pd
 
df = pd.DataFrame({
    "name": ["Alice", "Bob", "Charlie", "Diana"],
    "score": [88, 95, 72, 91],
    "department": ["Engineering", "Marketing", "Engineering", "Marketing"]
})
 
# Add a new column with a grade label
df["grade"] = df["score"].apply(lambda x: "A" if x >= 90 else ("B" if x >= 80 else "C"))
print(df)
#       name  score   department grade
# 0    Alice     88  Engineering     B
# 1      Bob     95    Marketing     A
# 2  Charlie     72  Engineering     C
# 3    Diana     91    Marketing     A

sort_values(key=)でのLambdaの使用

sort_values()keyパラメータは、ソート前にカラムに適用される関数を受け付けます:

import pandas as pd
 
df = pd.DataFrame({
    "product": ["Widget A", "Widget B", "Widget C"],
    "price": ["$29.99", "$9.50", "$149.00"]
})
 
# Sort by numeric price value (strip the $ sign first)
df_sorted = df.sort_values("price", key=lambda col: col.str.replace("$", "", regex=False).astype(float))
print(df_sorted)
#     product    price
# 1  Widget B    $9.50
# 0  Widget A   $29.99
# 2  Widget C  $149.00

apply()を行方向に使うLambda

各行にラムダを適用するにはaxis=1を設定します:

import pandas as pd
 
df = pd.DataFrame({
    "first_name": ["Ada", "Grace", "Alan"],
    "last_name": ["Lovelace", "Hopper", "Turing"],
    "birth_year": [1815, 1906, 1912]
})
 
# Create a full name column
df["full_name"] = df.apply(lambda row: f"{row['first_name']} {row['last_name']}", axis=1)
 
# Calculate age (approximate, as of 2026)
df["approx_age"] = df["birth_year"].apply(lambda y: 2026 - y)
 
print(df)
#   first_name last_name  birth_year       full_name  approx_age
# 0        Ada  Lovelace        1815  Ada Lovelace          211
# 1      Grace    Hopper        1906  Grace Hopper          120
# 2       Alan    Turing        1912    Alan Turing          114

一般的なLambdaパターンとイディオム

以下は、本番のPythonコードで頻繁に見かけるパターンです:

# 1. Default factory for collections.defaultdict
from collections import defaultdict
 
word_count = defaultdict(lambda: 0)
for word in ["apple", "banana", "apple", "cherry", "banana", "apple"]:
    word_count[word] += 1
print(dict(word_count))
# {'apple': 3, 'banana': 2, 'cherry': 1}
 
# 2. Immediate invocation (IIFE - Immediately Invoked Function Expression)
result = (lambda x, y: x + y)(3, 4)
print(result)
# 7
 
# 3. Lambda as a callback in GUI or event-driven code
# button.on_click(lambda event: print(f"Clicked at {event.x}, {event.y}"))
 
# 4. Using lambda with min/max for custom comparisons
products = [
    ("Laptop", 999),
    ("Mouse", 25),
    ("Keyboard", 75),
    ("Monitor", 450),
]
cheapest = min(products, key=lambda p: p[1])
print(cheapest)
# ('Mouse', 25)
 
# 5. Lambda with conditional expression for data cleaning
clean = lambda s: s.strip().lower() if isinstance(s, str) else s
print(clean("  Hello World  "))
# hello world
print(clean(42))
# 42

Lambdaを使うべきでない場合

Lambda関数には明確な限界があります。その限界を超えて使用すると、読みにくく、デバッグしにくく、保守しにくいコードになります。

以下の場合はLambdaを避けてください:

  1. ロジックが複雑な場合。 ネストされた条件、複数の操作、またはあらゆる形式のエラー処理が必要な場合は、defを使用してください。
# Bad -- hard to read
process = lambda x: x.strip().lower().replace(" ", "_") if isinstance(x, str) and len(x) > 0 else "empty"
 
# Good -- clear and testable
def process(x):
    """Normalize a string to a snake_case identifier."""
    if not isinstance(x, str) or len(x) == 0:
        return "empty"
    return x.strip().lower().replace(" ", "_")
 
print(process("  Hello World  "))
# hello_world
  1. 再利用のためにラムダを変数に代入する場合。 PEP 8は、ラムダに名前を付ける代わりにdefを使用することを明確に推奨しています。関数に名前を付ける価値があるなら、適切な定義を与えてください。

  2. docstringや型ヒントが必要な場合。 Lambda関数はどちらもサポートしていません。名前付き関数はサポートしています。

  3. デバッグが重要な場合。 Lambda関数はトレースバックで<lambda>として表示されるため、複数のラムダがある場合、どのラムダがエラーを引き起こしたか特定するのが困難です。

  4. 可読性が損なわれる場合。 同僚がラムダを理解するのに3秒以上かかる場合、名前付き関数として書き直してください。

状況lambdaを使用defを使用
sorted()のソートキーはい複雑な場合のみ
素早いmap()/filter()はい複数ステップの場合
複数の場所で再利用いいえはい
複雑な分岐いいえはい
docstringが必要いいえはい
APIでのコールバックはいロジックが増大する場合
エラー処理が必要いいえはい

RunCellでLambda関数を書いてリファクタリングする

JupyterノートブックでLambda関数を使うことは、データサイエンスワークフローでは一般的です。複雑なpandas apply()呼び出しを書いたり、複数のmap()filter()操作をチェーンしたりする際、ラムダが正しいツールなのか、名前付き関数にリファクタリングすべきかを判断するのが難しいことがあります。

RunCell (opens in a new tab)は、Jupyterノートブック内で直接動作するように設計されたAIエージェントです。ノートブックのコンテキスト -- メモリ内の変数、作業中のDataFrame、ロードされたインポート -- を理解し、的確な提案を行います。

RunCellがLambda関数に特化して役立つ方法:

  • Lambdaからdefへのリファクタリング。 ラムダが長くなりすぎた場合、RunCellは正確な動作を保持しながら、型ヒントとdocstring付きのクリーンなdefバージョンを提案できます。
  • パフォーマンスヒント。 大きなDataFrameでdf.apply(lambda ...)を使用している場合、RunCellはネイティブのpandasやNumPy操作を使用した、10〜100倍速いベクトル化された代替手段を提案できます。
  • インライン説明。 ネストされたラムダだらけの他人のコードを扱っている場合、RunCellはノートブック内で各ラムダが何をしているかを平易な言葉で分解できます。
  • パターン提案。 やりたいことを説明してください -- 「この辞書のリストを日付でソートし、次に名前でソートする」 -- RunCellが正しいラムダキー関数を持つ正しいsorted()呼び出しを生成します。

RunCellは既存のJupyter環境内で実行されるため、コンテキストの切り替えはありません。ノートブックにいたまま、AIエージェントがあなたと並んで作業します。

FAQ

PythonのLambda関数とは何ですか?

Lambda関数は、lambdaキーワードで定義される小さな匿名関数です。任意の数の引数を取ることができますが、単一の式のみを含むことができます。式の結果は自動的に返されます。Lambda関数は通常、ソートキー、map/filterコールバック、インライン変換などの短い使い捨て操作に使用されます。

Python Lambdaは複数行にできますか?

いいえ。Python Lambdaは単一の式に制限されています。ラムダ内で複数の文、ループ、代入を使用することはできません。複数行のロジックが必要な場合は、通常のdef関数を使用してください。ただし、単純な分岐のために、ラムダ内で条件式(a if condition else b)を使用することはできます。

Pythonでlambdaとdefの違いは何ですか?

どちらも関数オブジェクトを作成しますが、スコープが異なります:lambdaはインラインで使用される匿名の単一式関数を作成し、defは複数の文、docstring、型ヒント、デコレータを含むことができる名前付き関数を作成します。シンプルな1回限りの操作にはlambdaを使用し、名前、ドキュメント、複雑なロジックが必要なものにはdefを使用してください。

リスト内包表記の代わりにLambdaを使うべきなのはいつですか?

操作が単純で単一の変換または述語である場合は、map()filter()とラムダを使用してください。フィルタリングと変換の両方を1ステップで行う必要がある場合、またはロジックが[expr for x in iterable if condition]構造の恩恵を受ける場合は、リスト内包表記を使用してください。モダンPythonでは、可読性のためにリスト内包表記が一般的に好まれますが、ラムダはソートキーやコールバックパラメータの標準です。

Python Lambda関数は遅いですか?

いいえ。Lambda関数は同等のdef関数と同じパフォーマンスを持ちます。どちらを呼び出すオーバーヘッドも同一です。ただし、pandasでdf.apply(lambda ...)を使用することは、ベクトル化された操作と比較して遅いです。ボトルネックは行単位のPython実行であり、ラムダ自体ではありません。可能な限り、パフォーマンスを向上させるためにapply(lambda ...)を組み込みのpandasまたはNumPyメソッドに置き換えてください。

まとめ

Python Lambda関数は特定のニッチを埋めます:必要な場所に正確に定義する短い匿名関数です。ソートキー、map()/filter()コールバック、インライン変換として最も力を発揮します。sorted()map()filter()reduce()、pandas apply()と自然に組み合わせて使えます。

うまく使うためのルールは簡単です:

  • 1つのシンプルな式に留める。
  • インラインで使い、変数に代入しない(PEP 8ガイドライン)。
  • ロジックが読みにくくなった瞬間にdefに切り替える。
  • pandasでは、パフォーマンスのためにapply(lambda ...)よりもベクトル化された操作を優先する。
  • 条件式は控えめに使用する -- ラムダ内のネストされた三項演算子は可読性の罠。

Lambdaはツールであり、賢さの証ではありません。最良のPythonコードは、簡素化する場所でラムダを使い、明確化する場所でdefを使います。この2つの境界を知ることが、読みやすいコードと将来の自分(またはチームメイト)を苦しめるコードを分けるものです。

📚