Q1次のうち、正しいラムダ式はどれですか?
ラムダ式 lambda — 名前なし関数を 1 行で書く
Python のラムダ式 lambda を基礎から解説します。1 行で書く名前なし関数の書き方と高階関数との組み合わせまで図解で押さえます。
前回の高階関数では、関数を引数や戻り値として扱う仕組みを学びました。コールバックを渡すたびに def で関数を定義していると、1 行で済む処理にも 3〜4 行かかってしまいます。
そこで使われるのが、名前なしの関数を 1 行で書く ラムダ式(lambda)です。def で書くほどでもない小さな処理を、その場でサッと作れます。
ラムダ式とは — def と比べた書き方
ラムダ式の構文は lambda 引数: 式 です。式 の評価結果がそのまま戻り値になり、return は書きません(書くと SyntaxError)。
通常の関数と違って名前を持たないため、変数に代入しなければ呼び出すことができません。代入した変数名がそのままその関数の名前として使われます。
# def で書いた場合
def add_tax(price):
return int(price * 1.1)
print(add_tax(980)) # 1078
# 同じ処理をラムダ式で(return は書かない)
add_tax = lambda price: int(price * 1.1)
print(add_tax(980)) # 1078
「式」だけが書ける — 文は書けない
ラムダ式の本体には式(評価して値になるもの)しか書けません。if 文 や for 文・代入文(=)はそのまま書けず、複雑な処理を入れたくなったら素直に def に戻すのが正解です。
引数を増やす・条件式・デフォルト引数
ラムダ式は複数の引数も受け取れます。lambda x, y: x * y のようにカンマで区切って並べるだけです。
さらに、def の引数と同じくデフォルト引数も使えます。条件で値を切り替えたいときは三項演算子 値1 if 条件 else 値2 を式の中に書きます。
# 複数引数
rect_area = lambda width, height: width * height
print(rect_area(4, 5)) # 20
# デフォルト引数(rate を省略すると 0.1 として計算)
add_tax = lambda price, rate=0.1: int(price * (1 + rate))
print(add_tax(1000)) # 1100
print(add_tax(1000, 0.08)) # 1080
# 三項演算子で条件分岐
judge_age = lambda age: "成人" if age >= 20 else "未成年"
print(judge_age(25)) # 成人
print(judge_age(17)) # 未成年
# タプルで複数の値を返す
stats = lambda x, y: (x + y, x * y)
print(stats(3, 4)) # (7, 12)
lambda は 複数引数・デフォルト引数・三項演算子による分岐まで def と同じ感覚で書けます。高階関数と組み合わせる — ラムダ式の本領
ラムダ式の本当の出番は、高階関数の引数として「使い捨ての関数」を渡したいときです。たとえば sorted() の key 引数は、「並び替えのときに各要素から取り出すキーを返す関数」を受け取る高階関数です。
名前を付けて再利用するほどでもない並び順の指定は、key=lambda x: x["price"] のようにその場で書いて渡すのが最も自然です。
products = [
{"name": "ノート", "price": 480},
{"name": "ペン", "price": 120},
{"name": "消しゴム", "price": 80},
]
# 価格の安い順に並び替え(key にその場でラムダを渡す)
cheap_first = sorted(products, key=lambda item: item["price"])
for item in cheap_first:
print(item["name"], item["price"])
# 消しゴム 80
# ペン 120
# ノート 480
# 同じ高階関数 process_list でも、ラムダで処理を切り替えられる
def process_list(numbers, func):
for n in numbers:
print(func(n))
process_list([1, 2, 3, 4], lambda x: x ** 2)
# 1
# 4
# 9
# 16
ラムダ式の使いどころと避けどころ
ラムダ式は便利ですが、何でもラムダで書くのは逆に読みにくくなります。次の表のように、使い捨て・1 行で済む処理ならラムダ、複雑・繰り返し使う処理なら def、と棲み分けるのがおすすめです。
| 場面 | おすすめ | 理由 |
|---|---|---|
| sorted の key, filter, map に渡す | lambda | 1 行で意図が伝わり、名前を付ける必要もない |
| 税込み計算など 1 行で済む式 | lambda | 短い名前で関数化でき、import なしで使える |
| if / for / try が必要な処理 | def | lambda は式のみ。文を書こうとすると SyntaxError になる |
| 複数の場所から再利用される処理 | def | 名前で意図が伝わり、テストやドキュメントを書ける |
| 3 行以上の中身になる処理 | def | lambda に詰め込むほど読みづらくなる |
「lambda に何でも詰め込む」は禁物
三項演算子を 3 段重ねたり、複数の関数呼び出しを連結したりすると、1 行に収まっていても意味が読み取れないコードになります。「この lambda が何をしているか、コメントを書きたくなった」と感じたら、def を使いましょう。
理解度チェック
まずは1問ずつ答えてみましょう。
Q2次のコードを実行したときの出力はどれですか?f = lambda x, y=3: x ** y
print(f(2))
Q3次のうち、ラムダ式の使い方として最も適切なものはどれですか?