🐡

Python の無名関数

2021/10/02に公開

無名関数

無名関数は名前のない手続きを定義するための文法です。「手続き」という言葉の意味がわからなければ以下の記事の「手続きとは」の部分を参照してください。

https://zenn.dev/wsuzume/articles/cce908ba2b88dc

無名関数は、もともとはおそらくコンビネータ論理の\lambda計算に由来するもので、Python が属する手続き型言語とは異なる、関数型言語というタイプのプログラミング言語に取り入れられたものが、便利だったので手続き型言語に輸入されたものです[1]

無名関数を用いる動機

Python では関数を定義するとき

def func(x):
    return 2 * x

といった文法で定義します。関数型言語の世界では関数は第一級オブジェクトであり、と説明して通じるかはわかりませんが、要するに関数も変数と同じように「変数に代入する」ようなことができます。つまり関数を

func = ???

という文法で定義してもよいわけで、この「???」に入る、「まだ名前を持たない『手続き』を表現するオブジェクト」が無名関数です。

無名関数の文法

上で定義した x を 2 倍する関数は、\lambda計算における無名関数で表すと以下のような表記になります。

\lambda \, x. \, 2x

Python でもこれにならって、

lambda x: 2 * x

と書きます。よって

def func(x):
    return 2 * x

は、

func = lambda x: 2 * x

と定義することができ、上記の二つの書き方は等価になります[2]

二つ以上の引数を取る場合は以下のような書き方になります。

lambda x, y: x * y

無名関数は : の右側に改行を含む複雑な手続きを書くことはできません。すべてワンライナー[3]で書く必要があります。たとえば if にはワンライナー的な使い方があり、y に数値 x が 0 以上どうかを取得したいときは

y = True if x >= 0 else False

のような書き方をすることができます。これは無名関数の : の右側にも使えるので、

func = lambda x: True if x >= 0 else False

のように x が 0 以上かどうかを判定する関数を作ることができます。他にも for はリスト内包表記で

[ 2 * x for x in range(5) ]

のように使用することができますから、無名関数でも iffor を駆使して様々な処理を書くことができます[4]

無名関数を使うタイミング

無名関数は関数から名前を取り払っただけなので、名前のついた通常の関数ですべて置き換えることができます。したがって無理して使う必要はありません。

無名関数は、複数の関数を組み合わせて一度しか使わない関数を作るときに使います。具体的に言えば map 関数や filter 関数に渡す引数などに使います。

# 使用例1
for x in map(lambda x: 2 * x, range(10)):
    print(x)

# 使用例2
for x in filter(lambda x: x % 2 == 0, range(10)):
    print(x)

あると便利で、ないと寂しくなる便利機能ですね。

もっと無名関数をエンジョイしたい

エンジョイするためのライブラリを作りました。どうぞご利用ください。

https://zenn.dev/wsuzume/articles/9b9054289bc213

脚注
  1. この辺りの歴史はよく調べてないのであまり棒で叩かないでください。死んでしまいます。 ↩︎

  2. Python の内部でどうなっているかは知りませんが、少なくとも機能としてはほぼ同じはずです。キーワード引数まで使えるようなので多分まったく同じだと思います。 ↩︎

  3. 一行で書けるプログラムのこと。 ↩︎

  4. \lambda計算自体がチューリング完全なため原理的にはどんなプログラムでも書けるはずです。 ↩︎

Discussion