note.nkmk.me

Pythonの無名関数(ラムダ式、lambda)の使い方

Date: 2018-04-30 / tags: Python

Pythonではdef文で関数を定義するが、ラムダ式(lambda)で名前を持たない無名関数を作成することもできる。

ラムダ式は引数として関数(呼び出し可能なオブジェクト)を指定する場合などに使うと便利。書き方および使い方を説明する。

  • def文とlambda式の対応関係
  • lambda式でif文を使う
  • PEP8ではlambda式には名前を付けないのが推奨
  • lambda式の具体的な使い方・活用例
    • sorted(), sort(), max(), min()の引数keyに使う
    • map()filter()の第一引数に使う

def文による関数の定義については以下の記事を参照。

スポンサーリンク

def文とlambda式の対応関係

def文による関数定義とそれに相当するラムダ式での無名関数の作成は以下のようになる。便宜上、ラムダ式に名前を割り当てている(ラムダ式を変数に代入している)がPEP8では非推奨となっている。後述。

def 名前(引数, 引数, ...):
    return 

名前 = lambda 引数, 引数, ...: 

具体的には以下のようになる。この例のようにデフォルト引数を指定することもできる。

def add_def(a, b=1):
    return a + b

add_lambda = lambda a, b=1: a + b

print(add_def(3, 4))
# 7

print(add_def(3))
# 4

print(add_lambda(3, 4))
# 7

print(add_lambda(3))
# 4

lambda式でif文を使う

ラムダ式では複数行にまたがる文を使うことはできないが、if文に相当する三項演算子は使用可能。

get_odd_even = lambda x: 'even' if x % 2 == 0 else 'odd'

print(get_odd_even(3))
# odd

print(get_odd_even(4))
# even

三項演算子の書き方などの詳細は以下の記事を参照。

PEP8ではlambda式には名前を付けないのが推奨

これまでの例のようにラムダ式に名前を割り当てる(ラムダ式を変数に代入する)とPythonのコーディング規約PEP8の自動チェックツールなどでWarningが出ることがある。

Do not assign a lambda expression, use a def (E731)

ラムダ式は呼び出し可能なオブジェクトを引数で渡すときなどに名前を付けずに使うためのもので、名前を付けて関数を定義する場合はdefを使うべき、というのがPEP8の考え方。

あくまでもコーディング規約PEP8の推奨で、Pythonの文法的にはエラーではなく実行可能。

lambda式の具体的な使い方・活用例

sorted(), sort(), max(), min()の引数keyに使う

リストをソートする組み込み関数sorted()やリストのメソッドsort()、最大値や最小値を返す組み込み関数max()min()には引数keyがある。

keyには、ソートや最大値・最小値の算出の前に(各要素が比較される前に)リストの各要素に適用される関数を指定する。

組み込み関数sorted()を例に説明する。

文字列のリストは、デフォルトではアルファベット順にソートされる。

l = ['Charle', 'Bob', 'Alice']

l_sorted = sorted(l)

print(l_sorted)
# ['Alice', 'Bob', 'Charle']

文字数を返す組み込み関数len()を引数keyに指定すると、文字数が少ない順にソートされる。

print(len('Alice'))
# 5

l_sorted_len = sorted(l, key=len)

print(l_sorted_len)
# ['Bob', 'Alice', 'Charle']

ここでラムダ式を使うと、任意の関数を各要素に適用してその結果を元にソートできる。例えば2文字目を取得するラムダ式を引数keyに指定すると、2文字目のアルファベット順にソートされる。

print((lambda x: x[1])('Alice'))
# l

l_sorted_second = sorted(l, key=lambda x: x[1])

print(l_sorted_second)
# ['Charle', 'Alice', 'Bob']

もちろんdef文で関数を定義してkeyに指定してもいいが、そのあと同じ関数を繰り返し使うのでなければラムダ式で書いたほうが無駄がない。

map()やfilter()の第一引数に使う

リストの各要素に対して関数を適用する組み込み関数map()や、条件を満たす要素のみ抽出する組み込み関数filter()では、第一引数に関数、第二引数にリストなどのイテラブルオブジェクトを指定する。

任意の関数を指定したい場合、def文で関数を定義するよりラムダ式で無名関数を指定したほうが簡潔に書ける。

なお、map()関数やfilter()関数と同様の処理はリスト内包表記やジェネレータ式(ジェネレータ内包表記)でも書ける。これについても例を示す。

書籍『Effective Python』ではmap()関数やfilter()関数よりもリスト内包表記やジェネレータ式(ジェネレータ内包表記)を使うのが推奨されている。

map()関数の例

map()関数の例として、第一引数に値を二乗するラムダ式を指定する。

l = [0, 1, 2, 3]

map_square = map(lambda x: x**2, l)

print(map_square)
# <map object at 0x1072fd128>

print(list(map_square))
# [0, 1, 4, 9]

Python3からmap()はリストではなくイテレータを返すようになったので注意。

リストを取得したい場合はリスト内包表記でも書ける。ラムダ式を書くより簡潔。

l_square = [x**2 for x in l]

print(l_square)
# [0, 1, 4, 9]

イテレータを取得したい場合はジェネレータ式(ジェネレータ内包表記)を使う。

g_square = (x**2 for x in l)

print(g_square)
# <generator object <genexpr> at 0x1072b6d00>

print(list(g_square))
# [0, 1, 4, 9]

filter()関数の例

filter()関数の例として、第一引数に偶数を真Trueとするラムダ式を指定する。

filter()map()と同様にPython3からはイテレータを返すようになっている。

filter_even = filter(lambda x: x % 2 == 0, l)

print(list(filter_even))
# [0, 2]

これもリスト内包表記やジェネレータ式(ジェネレータ内包表記)でも書ける。

l_even = [x for x in l if x % 2 == 0]

print(l_even)
# [0, 2]

リストの要素の抽出などについて、より詳しくは以下の記事を参照。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事