【Python入門】lambda(無名関数、ラムダ式)が使えるようなる

doya_face list

サンプルコードに突如あらわれるlambda。
テンションがいっきに下がるキーワードですが、一度は通る道なので、ポイントだけ理解しておきましょう。

関数の作り方

Pythonでは、オリジナルの関数を作る方法が2つあります。
・def文(関数名で定義)
・無名関数

<ポイント>
lambdaは、関数に名前を付けないオリジナルの関数(無名関数)です。

def文のブロックで、関数を作る

関数の定義は、関数名に引数と返り値を指定して行います。

def 関数名(引数):
    return 返り値

関数の使い方は、関数名に引数を指定して呼び出します。

関数名(引数)


引数を10倍する関数func_x10を作ります。

# 関数の定義
def func_x10(x):
    return x * 10
# 関数の呼び出し
func_x10(1)
10

無名関数で、関数を作る

関数の定義は、def文と同じく引数と返り値を指定して行います。
関数名はありません。

説明の都合で、変数に代入して、def文と比較します。

変数名 = lambda 引数: 返り値

無名関数の使い方は、def文と同じです。
関数名がないので、変数名で呼び出します。

変数名(引数)


引数を10倍する無名関数を作り、変数x10に代入します。

# 関数の定義
x10 = lambda x: x * 10
# 関数の呼び出し
x10(1)
10


<ポイント>
def文も無名関数も同じ関数だとわかります。

def文と無名関数(lambda、ラムダ式)の違い

def文と無名関数は、 関数を作る点では同じことをしています。
違う点は、関数名のあり・なしと、関数を定義する書式です。

あと、無名関数は1行で書く必要があります。

無名関数の使いどころ

通常の処理は、def文で関数を作る方が柔軟性があり、可読性が高いです。

無名関数は、引数に関数を受け取る関数などに使用すると、簡潔にコードが書けます。
簡潔なコードは、必ずしも可読性が高いわけではないですが、ドヤ顔感が高まります。

具体例としては、
・引数key: list.sort(key=無名関数)、sorted( 第一引数, key=無名関数)
・filter(無名関数, 第二引数)
・map(無名関数, 第二引数)

<ポイント>
lambdaは、引数に関数を受け取る関数に使用する。
言い換えると、関数に渡す引数(=関数)として使用する。

list.sort( key=無名関数)

組み込み関数list.sort()を使って、データの並び替えをします。

ページ番号のような文字列をソートすると、数値の大小ではソートされません。

list_str = list(['P1', 'P2', 'P3', 'P4', 'P10'])
list_str.sort()
print(list_str)
['P1', 'P10', 'P2', 'P3', 'P4']


このようなとき、2文字目以降を数値へ変換してkeyに指定すると、数値の大小でソートできます。

list_str = list(['P1', 'P2', 'P3', 'P4', 'P10'])
list_str.sort(key=lambda x: int(x[1:]))
print(list_str)
['P1', 'P2', 'P3', 'P4', 'P10']

文字列「P」以降の数値を取り出す無名関数で、データをソートすることができました。

無名関数を変数に代入して、keyパラメーターが関数を受け取ることを強調してみます。

list_str = list(['P1', 'P2', 'P3', 'P4', 'P10'])
func_int = lambda x: int(x[1:]) # 無名関数を変数に代入

list_str.sort(key=func_int)
print(list_str)
['P1', 'P2', 'P3', 'P4', 'P10']

無名関数を変数に代入するのは、推奨されている記述方法ではありませんが、「引数に関数を受け取る関数」という感じがでていると思います。

sorted( 第一引数, key=無名関数)

list.sort()の例と同じように、sorted()でkeyを指定してソートしてみます。

list_str = list(['P1', 'P2', 'P3', 'P4', 'P10'])
sorted(list_str, key=lambda x: int(x[1:]))
['P1', 'P2', 'P3', 'P4', 'P10']

lambda以降の1文が、関数に見えてきたでしょうか。

filter(無名関数, 第二引数)

組み込み関数filter()を使って、リストから特定の要素を抽出します。

リストから偶数のページ番号を抽出します。
ページ番号を2で割った余りが0になる要素が、偶数のページ番号です。
filter関数の返り値は、list型にすると要素を見ることができます。

list_str = list(['P1', 'P2', 'P3', 'P4', 'P10'])
list_EvenNumber = list(filter(lambda x: int(x[1:])%2 == 0, list_str))
print(list_EvenNumber)
['P2', 'P4', 'P10']

リスト「list_str」から無名関数で、偶数のページ番号を抽出することができました。

無名関数を変数に代入して、第一引数が関数を受け取ることを強調してみます。

list_str = list(['P1', 'P2', 'P3', 'P4', 'P10'])
EvenNumber = lambda x: int(x[1:])%2 == 0   # 無名関数を変数に代入

list_EvenNumber = list(filter(EvenNumber, list_str))
print(list_EvenNumber)
['P2', 'P4', 'P10']


組み込み関数filter(第一引数, 第二引数)の返り値は、第二引数の要素に対して、第一引数の関数を実行した結果がTrueになる要素です。

def文だと、次のようになります。

list_str = list(['P1', 'P2', 'P3', 'P4', 'P10'])

# 偶数ページはTrue、奇数ページはFalseを返す関数
def func_EvenNumber(x):
    if int(x[1:])%2 == 0:
        binary =  True
    else:
        binary = False
        
    return binary    


list_EvenNumber = list(filter(func_EvenNumber, list_str))   
print(list_EvenNumber)
['P2', 'P4', 'P10']

組み込み関数filter()の第一引数で指定した関数を実行した結果がTrueになる要素を抽出することができました。

def文で関数を定義すると、ずいぶんと長いコードになりますね。

map(無名関数, 第二引数)

組み込み関数map()を使って、リストの要素を10倍にします。

map関数は、filter関数と同じように、第二引数の要素に対して、第一引数の関数を実行します。

list_num = list([1, 2, 3, 4, 5])

list_x10 = list(map(lambda x: x * 10, list_num))
print(list_x10)
[10, 20, 30, 40, 50]

まとめ

  • lambdaは、オリジナルの関数を作ることができる(無名関数)
  • lambdaは、関数の引数(=関数)として使用する


lambdaがmap関数のような関数の引数として使われる場合、そもそもmap関数の使い方が難しいです。
list(map(lambda, リスト)))だと、3重の入れ子になっているので、混乱してしまいます。

1つ1つ関数の構造を分解して、コードの処理を理解してください。

関連情報

タイトルとURLをコピーしました