Pythonのラムダ(lambda)式の使い方、気になっていませんか?
「lambdaって一体何者?」「defと何が違うの?」そんな疑問を抱えているかもしれませんね。Pythonのコードをもっと短く、シュッとさせたいなら、ラムダ式は知っておいて損はないテクニックですよ。
この記事では、Pythonのラムダ式について、基本のキから、実際のコードでどう使うか、どんな時に便利なのかを、初心者の方にも分かりやすく解説していきます。
map()やfilter()といった便利な関数と組み合わせる方法も紹介するので、読み終わるころにはラムダ式マスターに近づいているはず!
この記事で学べること
- ラムダ式が何なのか、基本的な考え方
- ラムダ式を使うとどんな良いことがあるのか
- ラムダ式の基本的な書き方とルール
- defで定義する普通の関数との違い
- map()やfilter()関数と組み合わせた実践的な使い方
- ラムダ式を使うときの注意点
Pythonのラムダ式とは?
ラムダ式は、名前を持たない小さな関数を作るための書き方です。
普通の関数は `def` キーワードを使って名前を付けて定義しますよね。でも、ちょっとした処理のためだけに、いちいち名前を考えるのが面倒な時もあります。
そんな時に登場するのがラムダ式! `lambda` というキーワードを使って、一行でサクッと関数を定義できちゃうんです。
例えば、受け取った数字を2倍にするだけの処理を考えてみましょう。
`def` を使うとこんな感じ。
def double(x): return x * 2
ラムダ式なら、こう書けます。
lambda x: x * 2
ほら、短いでしょ? この「名前がなくて一行で書ける」のがラムダ式の大きな特徴なんです。
ラムダ式のメリット
「わざわざラムダ式なんて覚えなくても、`def` で全部書けばいいじゃん」と思うかもしれません。
確かにそれでも動きますが、ラムダ式を知っていると、もっと効率よく、そしてカッコよくコードが書ける場面があるんです!
ラムダ式を使う主なメリットはこんな感じです。
- コードが短く、簡潔になる
簡単な処理なら、`def` で数行書くよりもラムダ式一行のほうがスッキリします。 - `map()` や `filter()` などの引数として使いやすい
後で詳しく説明しますが、リストの各要素に同じ処理をしたり、条件に合う要素だけを選び出したりする関数(高階関数といいます)に、処理内容をサッと渡すのにとても便利です。 - 一時的な使い捨て関数として便利
その場でしか使わないような、ごく簡単な処理を定義するのにピッタリ。わざわざ名前を付けて `def` で定義するほどでもない場合に重宝します。
例えば、リストの数字を全部2倍にしたい時、`def` を使うとこうなりますが…
def double(x): return x * 2 numbers = [1, 2, 3, 4, 5] doubled_numbers = map(double, numbers) print(list(doubled_numbers)) # list()で囲むのを忘れずに!
ラムダ式なら `map()` の中に直接書けちゃいます。
numbers = [1, 2, 3, 4, 5] doubled_numbers = map(lambda x: x * 2, numbers) print(list(doubled_numbers))
どうでしょう? `def` の部分がなくなって、コード全体が短くなりましたよね!
ラムダ式の基本的な書き方
さて、いよいよラムダ式の書き方を見ていきましょう。構文はとってもシンプルです。
lambda 引数: 式(処理内容)
分解してみると…
- `lambda` これはおまじない。ラムダ式を始めるときの合言葉です。
- `引数` 関数が受け取る値のこと。カンマ区切りで複数指定もOK。引数が不要な場合は書かなくても大丈夫ですが、あまりそういうケースはありません。
- `:` コロンを忘れずに!引数と処理内容を区切る役割です。
- `式(処理内容)` 引数を使って行う計算や処理を書きます。ここには一つの式しか書けません。 結果が自動的に返されます (`return` は書きません)。
いくつか例を見てみましょう。
引数を1つ受け取り、2倍にして返すラムダ式
lambda x: x * 2
引数を2つ受け取り、足し算して返すラムダ式
lambda x, y: x + y
引数を受け取らず、常に `"Hello"` という文字列を返すラムダ式(あまり使わない例)
lambda: "Hello"
ね、簡単でしょ? `def` と違って、`return` を書かなくても、式の評価結果がそのまま戻り値になるのがポイントです。
簡単なサンプルコードでPythonラムダ式の使い方を体験
ラムダ式がなんとなく分かってきたところで、実際に動かして使い方を体験してみましょう!
ラムダ式は、変数に入れて普通の関数みたいに使うこともできます。
# ラムダ式を変数 multiply に代入 multiply = lambda x, y: x * y # 変数を使ってラムダ式を呼び出す result = multiply(3, 5) print(result) # 3 * 5 の結果が表示されるはず
表示結果
15
もちろん、変数に入れずに、その場で直接使うことも可能です。
# ラムダ式を定義して、その場で引数 (4, 6) を渡して呼び出す result = (lambda x, y: x + y)(4, 6) print(result) # 4 + 6 の結果が表示される
表示結果
10
ポイントは、ラムダ式全体をカッコ `()` で囲んで、その後ろに呼び出すための引数を `()` で渡すことです。
ちょっと見慣れない書き方かもしれませんが、こうやって一時的な関数として使えるのがラムダ式の面白いところですね。
ラムダ式とdefで作る関数の違いは?使い分けを理解しよう
ラムダ式と `def` で定義する関数、どちらも関数を作る方法ですが、いくつか違いがあります。その違いを知っておくと、どっちを使うべきか迷ったときに役立ちますよ!
- 名前の有無
`def` は関数に名前を付けますが、ラムダ式は名前のない匿名関数です。(変数に代入すれば名前を付けたようには扱えますが、本質的には無名です。) - 書ける処理の複雑さ
`def` は複数行にわたる複雑な処理や、if文、for文なども自由に書けます。一方、ラムダ式は単一の式しか書けません。 複雑な処理は書けないんです。 - 文か式か
`def` は関数を定義するための「文」です。それに対して、ラムダ式は関数オブジェクトを生成する「式」です。式なので、関数の引数など、式が書ける場所にならどこにでも書けます。
じゃあ、どう使い分けるのが良いのでしょうか?
- `def` を使う場面
- 処理が複雑で複数行にわたる場合
- 同じ処理をプログラムのあちこちで何度も使いたい場合(名前があったほうが呼びやすい!)
- クラスのメソッドを定義する場合
- ラムダ式を使う場面
- `map()`, `filter()`, `sorted()` などの引数として、ちょっとした処理を渡したい場合
- 一度しか使わないような、ごく簡単な処理をその場で定義したい場合
- コードをできるだけ短く書きたい場合(ただし、分かりにくくならない範囲で!)
基本的には、簡単な処理をサッと書きたいときはラムダ式、それ以外は `def` と覚えておくと良いでしょう。
ラムダ式の便利な使い方① map関数との組み合わせ
`map()` 関数は、リストやタプルのようなデータ(イテラブルといいます)の各要素に対して、指定した関数を適用して、新しいイテラブルを作る関数です。
例えば、「リストの数字を全部2倍にしたい」とか「リストの文字列を全部大文字にしたい」といった場合に役立ちます。
この `map()` の第一引数(適用する関数)に、ラムダ式を渡すと非常にコードがスッキリするんです!
リストの各要素を2乗する例
numbers = [1, 2, 3, 4, 5] # mapの第一引数に「受け取った値を2乗する」ラムダ式を渡す squared_numbers_map = map(lambda x: x**2, numbers) # mapの結果はそのままでは見れないのでlist()でリストに変換 squared_numbers_list = list(squared_numbers_map) print(squared_numbers_list)
もし `def` を使うと、まず関数を定義してから `map` に渡す必要があるので、少しコードが増えますよね。ラムダ式なら、処理内容を `map` の中に直接書き込めるので、コードが短くまとまります。
map関数とラムダ式を使ったサンプルコード
もう少し `map` とラムダ式の組み合わせ例を見てみましょう。コピペして試してみてくださいね。
数値リストの各要素に10を足す
scores = [70, 85, 90, 60] # 各要素に10を足すラムダ式 adjusted_scores_map = map(lambda x: x + 10, scores) adjusted_scores_list = list(adjusted_scores_map) print(f"元の点数: {scores}") print(f"調整後の点数: {adjusted_scores_list}")
表示結果
元の点数: [70, 85, 90, 60] 調整後の点数: [80, 95, 100, 70]
文字列リストの各要素の先頭に "Mr." を付ける
names = ["Tanaka", "Suzuki", "Sato"] # 各文字列の先頭に "Mr. " を付けるラムダ式 mr_names_map = map(lambda name: "Mr. " + name, names) mr_names_list = list(mr_names_map) print(f"元の名前リスト: {names}") print(f"敬称付き名前リスト: {mr_names_list}")
表示結果
元の名前リスト: ['Tanaka', 'Suzuki', 'Sato'] 敬称付き名前リスト: ['Mr. Tanaka', 'Mr. Suzuki', 'Mr. Sato']
注意点として、`map()` 関数の結果は `map` オブジェクトという特殊な形で返ってきます。 そのままでは中身が見えにくいので、`list()` 関数などを使ってリストやタプルに変換してから使うのが一般的ですよ。
ラムダ式の便利な使い方② filter関数との組み合わせ
`filter()` 関数は、リストなどのイテラブルから、条件に合う要素だけを抽出(フィルタリング)して、新しいイテラブルを作る関数です。
「リストの中から偶数だけ取り出したい」とか「リストの中から特定の文字で始まる単語だけ選びたい」といった場合に活躍します。
`filter()` の第一引数には、条件を判定する関数を渡します。この関数が `True` を返した要素だけが抽出される仕組みです。そして、ここでもラムダ式が大活躍! 条件判定の処理をラムダ式で簡潔に書けることが多いんです。
リストから偶数だけを抽出する例
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # filterの第一引数に「偶数かどうか判定する」ラムダ式を渡す # x % 2 == 0 は、xを2で割った余りが0(つまり偶数)ならTrueを返す even_numbers_filter = filter(lambda x: x % 2 == 0, numbers) # filterの結果もそのままでは見れないのでlist()でリストに変換 even_numbers_list = list(even_numbers_filter) print(even_numbers_list)
`def` で判定関数を別に定義するよりも、`filter` の中に直接ラムダ式を書くほうが、何でフィルタリングしているのか分かりやすい場合がありますね。
filter関数とラムダ式を使ったサンプルコード
`filter` とラムダ式の組み合わせ例も見てみましょう。これもコピペOKです!
数値リストから5より大きい値だけを抽出
data = [3, 7, 2, 8, 5, 10, 4, 9] # 値が5より大きいか判定するラムダ式 greater_than_5_filter = filter(lambda x: x > 5, data) greater_than_5_list = list(greater_than_5_filter) print(f"元のデータ: {data}") print(f"5より大きい値: {greater_than_5_list}")
表示結果
元のデータ: [3, 7, 2, 8, 5, 10, 4, 9] 5より大きい値: [7, 8, 10, 9]
文字列リストから長さが5文字以上の単語だけを抽出
words = ["apple", "banana", "cherry", "date", "fig", "grape"] # 文字列の長さ(len())が5以上か判定するラムダ式 long_words_filter = filter(lambda s: len(s) >= 5, words) long_words_list = list(long_words_filter) print(f"元の単語リスト: {words}") print(f"5文字以上の単語: {long_words_list}")
表示結果
元の単語リスト: ['apple', 'banana', 'cherry', 'date', 'fig', 'grape'] 5文字以上の単語: ['apple', 'banana', 'cherry', 'grape']
`filter()` の結果も `map()` と同じく、そのままでは扱いにくいイテレータなので、`list()` などで変換するのを忘れないようにしましょう。 これ、結構忘れがちなので気をつけてくださいね!
ラムダ式の便利な使い方③ sorted関数やリストのsortメソッドとの組み合わせ
データを並べ替えたいとき、Pythonには `sorted()` 関数(新しいソート済みリストを返す)や、リスト自体の `sort()` メソッド(元のリストを直接ソートする)があります。
普通に使うと、数値なら昇順、文字列なら辞書順に並びますが、もっと複雑なルールで並べ替えたい時ってありますよね?例えば、「タプルのリストを、タプルの2番目の要素で並べ替えたい」とか。
そんな時に役立つのが `key` という引数です。この `key` に関数を渡すと、その関数が各要素に適用され、その関数の戻り値を使って並べ替えが行われます。
そして、もうお分かりですね? この `key` に渡す「並べ替えの基準を作る関数」として、ラムダ式がめちゃくちゃ便利なんです!
タプルのリストを、各タプルの2番目の要素(インデックス1)でソートする例
items = [('apple', 5), ('banana', 2), ('cherry', 8)] # keyに「タプルの2番目の要素(x[1])を返す」ラムダ式を指定 sorted_items = sorted(items, key=lambda x: x[1]) print(f"元のリスト: {items}") print(f"2番目の要素でソート後: {sorted_items}")
表示結果
元のリスト: [('apple', 5), ('banana', 2), ('cherry', 8)] 2番目の要素でソート後: [('banana', 2), ('apple', 5), ('cherry', 8)]
辞書のリストを、'age' というキーの値でソートする例
users = [ {'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 35} ] # keyに「辞書の'age'の値を返す」ラムダ式を指定 sorted_users = sorted(users, key=lambda user: user['age']) print(f"元のリスト: {users}") print(f"年齢でソート後: {sorted_users}")
表示結果
元のリスト: [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 35}] 年齢でソート後: [{'name': 'Bob', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Charlie', 'age': 35}]
`key` にラムダ式を使うことで、わざわざソート用の関数を `def` で定義しなくても、その場でサッと並べ替えのルールを指定できるのが大きなメリットです。
ラムダ式の使い方における注意点やデメリット
ラムダ式は便利ですが、万能薬ではありません。使い方を間違えると、逆にコードが分かりにくくなってしまうことも…。いくつか注意点を知っておきましょう。
- 複雑な処理は書けないし、書くべきでない
ラムダ式で書けるのは単一の式だけです。`if` 文を無理やり条件式で表現したり、何段階もの処理を一行に詰め込んだりすると、解読不能なコードになりがちです。処理が少しでも複雑になるなら、迷わず `def` で普通の関数を定義しましょう。 - デバッグがしにくいことがある
ラムダ式は名前がないので、エラーが発生したときに、どこで問題が起きたのか特定しにくい場合があります。`def` で定義した関数なら、エラーメッセージに関数名が表示されるので、原因究明がしやすいです。 - 再利用には向かない
同じような処理を何度も書くくらいなら、`def` で関数を定義して、それを呼び出す方が効率的です。 - 読みやすさを常に意識する
ラムダ式は短く書けますが、それが必ずしも読みやすいとは限りません。特にPythonに慣れていない人が読む場合、`def` で書かれた方が処理の流れを追いやすいこともあります。「短さ」よりも「分かりやすさ」を優先しましょう。
良くない例(無理にラムダ式を使っている)
# 複雑な条件分岐をラムダ式で書こうとすると…読みにくい! complex_logic = lambda x: "positive" if x > 0 else ("negative" if x < 0 else "zero") print(complex_logic(5)) print(complex_logic(-3)) print(complex_logic(0))
改善例(`def` を使う)
def get_sign(x): if x > 0: return "positive" elif x < 0: return "negative" else: return "zero" print(get_sign(5)) print(get_sign(-3)) print(get_sign(0))
下の `def` を使った方が、処理内容がパッと見て分かりやすいですよね? ラムダ式は、あくまでも「シンプルで短い処理」に使うのがコツです。
【まとめ】Pythonのラムダ式の使い方をマスターして効率化しよう!
Pythonのラムダ式について、基本的な考え方から実践的な使い方、注意点まで見てきました。
最後に、今回学んだことをおさらいしましょう。
- ラムダ式は `lambda 引数: 式` で書ける、名前のない一行関数。
- コードを短く書けたり、`map` や `filter`、`sorted` の引数として使うと便利。
- `def` との違いは、名前の有無、書ける処理の複雑さ(ラムダは単一式のみ)。
- 複雑な処理や再利用する場合は `def`、簡単な一時的処理にはラムダ式が向いている。
- 使いすぎると読みにくくなるので、分かりやすさを第一に考える。
ラムダ式は、Pythonのコードをより洗練させるためのテクニックの一つです。最初はちょっと戸惑うかもしれませんが、`map` や `filter` と一緒に使ってみると、その便利さが実感できるはずです!
ぜひ、今回紹介したサンプルコードを動かしたり、自分のコードの中で簡単な処理をラムダ式で書き換えられないか試してみてください。実際に手を動かすのが、一番の近道ですよ!
ラムダ式を使いこなして、もっとPythonプログラミングを楽しんでいきましょう!
【関連記事】 「Pythonとは?」に答える最初の一歩
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。