Pythonでは無名関数も定義できる。これにはlambdaキーワードを使用して「ラムダ式」として記述する。ラムダ式の構文を以下に示す。
lambda パラメーターリスト: 式
これはdefキーワードによる以下の関数定義とおおよそ同値である(ただし、ラムダ式で作成される関数には名前はなく、関数名は得られないので「……」としてある)。
def ……(パラメーターリスト):
return 式
ラムダ式では関数のボディーに相当する部分には単一の「式」しか記述できない。このことから分かるように、ラムダ式は極めて小さな処理を関数の形でインラインに記述する場合に使用するのが主な用途となる。ただし、以下ではまずラムダ式で作成した関数オブジェクトを変数に代入して使用してみよう。
>>> (lambda x, y: x + y)(1,2)
3
>>> add = lambda x, y: x + y
>>> add(2, 4)
6
最初の例はラムダ式が返す無名関数をそのまま呼び出している。次の例では、変数addにラムダ式が返す無名関数を代入し、その変数を利用して関数呼び出しを行っている。
次のようなこともできる。
>>> makeadder = lambda x: lambda y: x + y
>>> adder2 = makeadder(2)
>>> adder2(100)
102
一見すると分かりにくいが、最初の行は「lambda x: (lambda y: x + y)」とかっこを入れてみると少しは理解しやすくなるかもしれない。これはラムダ式を返すラムダ式ということだ。そして、返送されるラムダ式では最初のラムダ式に渡された引数にアクセスできる(よって、adder2はパラメーターyに渡された値に、元のラムダ式のパラメーターxに渡された値=2を加算した値を返す関数となる)。
実際の使いどころとしてよく挙げられるのは、Pythonに組み込みの関数mapと組み合わせて利用することだ。関数mapはパラメーターに関数と反復可能なオブジェクトを取り、後者に対して連続的に関数を適用する反復可能オブジェクト(イテラブル、iterable)を返す。以下に例を示す。
>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(map(lambda x: x * 2, l)) # 使い捨ての処理をインラインで記述
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
defキーワードで定義する関数を利用しても以下のように記述してももちろん構わない。
>>> def dbl(x):
... return x * 2
...
>>> list(map(dbl, l))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
だが、上のようにちょっとした処理を行うだけの関数をわざわざ定義するのではなく、インラインでサクサクと書けるのがラムダ式(無名関数)のよいところだ(もちろん、関数mapに渡す関数でより入り組んだ処理を行うのであれば、関数を別途定義するのがよい)。
これまでの例でも出てきたが、Pythonでは関数も他のオブジェクトと同様に、関数に引数として渡したり、関数の戻り値として返送したりできる。このような関数を引数/戻り値として扱える関数のことを「高階関数」と呼ぶ。
例えば、先ほど見たラムダ式を返すラムダ式は高階関数の一例だ。また、map関数はパラメーターに関数を受け取るので、これも高階関数である。先ほどの例とあまり変わらないが、もう1つの例としてPythonに組み込みの関数filterを今度は見てみよう。
>>> list(filter(lambda x: not x % 2, l))
[0, 2, 4, 6, 8]
関数filterは受け取った関数を反復可能オブジェクトの要素に適用し、その値が真となるものだけを要素とする反復可能オブジェクトを返す。Pythonでは「0、空文字列、要素のないリスト/辞書/タプル/集合」なども偽として扱われるので、上では「x % 2」に「not」を付加することで偶数のみからなるリストを作成している。同様に関数を渡すことで、処理に介入できる関数としてはリストのsortメソッドや組み込み関数sortedなどがある。
次に関数とよく似たジェネレーターについて見てみよう。
Copyright© Digital Advantage Corp. All Rights Reserved.