[Python入門]ローカル関数とラムダ式:Python入門(1/3 ページ)
Pythonでは、関数を変数に代入したり、関数の引数や戻り値に使用したりできる。この特性と、簡潔に関数を記述できるようにするラムダ式について見ていく。
* 本稿は2019年5月28日に公開された記事を、Python 3.12.0で動作確認したものです(確認日:2023年10月16日)。
前回は、Pythonの関数におけるローカル変数の特徴をスタート地点として、変数のスコープや名前空間について見た。今回は関数をオブジェクトとして扱う方法、ローカル関数、ラムダ式といった高度な話題を取り上げる。
関数を変数に代入してみる
Pythonでは「1」「0.1」のような数値も、'Python'のような文字列も「オブジェクト」である。この話自体は第3回「数値と算術演算」の「Pythonで計算してみよう」などでも話している。そして、Pythonでは「関数もオブジェクト」であり、変数に関数を代入したり、関数に引数として関数を渡したりといったことができる。文章だけではよく分からないので、ちょっと実際に試してみよう。
mylen = len # 組み込みのlen関数を変数mylenに代入
print(mylen('Python')) # 「mylen関数」を呼び出す
上のコードの1行目では、Pythonに組み込みのlen関数を変数mylenに代入している。このとき、関数呼び出し時に付加するかっこ「()」がないことに注意しよう(なお、「len」という名前は、前回に話した名前解決の過程を経て、ビルトイン名前空間にあるlen関数に解決される)。
このように「関数を変数に代入」すると、今度は「代入した変数を使ってその関数を呼び出す」ことが可能になる。それを実際に行っているのが2行目のコードだ。このときには、かっこ「()」を付けてその中に引数を記述することで「関数を呼び出している」ことを明示する。
実行結果を以下に示す。
変数mylenにかっこと引数を付加して呼び出すことで、len関数と同じものが実行され、文字数が表示された。
このことから、Pythonでは「変数に関数を代入できる」ことが分かる。このとき「len('Python')」のように元の名前で関数を呼び出すことももちろんできる。つまり、「len」と「mylen」という2つの名前は共に、コンピュータのメモリ上に存在する関数の実体(オブジェクト)を参照しているということだ。
このように、Pythonでは関数も数値や文字列と同じように、変数に代入することが可能だ。さらに、「関数を引数に受け取る関数」や「関数を戻り値とする関数」もある。これらについても簡単に見てみよう。
関数を受け取る関数
関数を引数に受け取る関数もある。組み込みのtype関数がその一つだ。type関数に引数を1つだけ渡すと、渡されたオブジェクトの型が返される。この関数にlen関数を渡してみよう。
print(type(len))
実行結果は次のようになる。
「<class 'builtin_function_or_method'>」と表示された。詳しい解説は省略するが、これは「len関数の型がbuiltin_function_or_methodである」(len関数はbuiltin_function_or_methodクラスのインスタンス)であることを表している。そのことはともかくとして、数値や文字列と同じように、関数に引数として関数を渡せることがこれで分かった。
もちろん、関数を受け取る関数を定義することも可能だ。以下に例を示す。
def apply(func, param):
return func(param)
この関数は、最初のパラメーターfuncに関数を受け取り、次のパラメーターparamに第1パラメーターに受け取った関数を呼び出す際に指定する引数を受け取り、それらを使って関数呼び出しを行って、その結果を戻り値とするものだ。実際に使ってみよう。
apply(len, 'Python')
上のコードでは、第1引数にはlen関数を、第2引数には文字列'Python'を指定しているので、apply関数の内部では「func(param)」は「len('Python')」となる。つまり、文字列'Python'の文字数がapply関数の戻り値となる。
このように数値や文字列などと同様に「関数を関数の引数」とすることも可能だ。ここまでに「変数に関数を代入する」「関数を関数の引数にする」ことができるのを見てきた。では、「関数を関数の戻り値にする」ことは可能だろうか。もちろん、可能だ。
関数を返す関数(ローカル関数の定義)
関数を関数の戻り値にすることも可能だ。それにはdef文の中で、さらにdef文を使って関数を定義して、定義した関数をreturn文で戻してやればよい。このような関数定義の中で定義する関数のことを「ローカル関数」と呼ぶこともある。以下に例を示す。
def make_adder(x):
def adder(y):
return x + y
return adder
慣れていないうちは少し難しいかもしれないが、このコードが何をしているかを見てみよう。make_adder関数の中ではローカル関数「adder」を定義して、それを戻り値としている。make_adder関数はパラメーターを1つ持つが、adder関数の中ではそれを利用していることにも注目しよう。adder関数はパラメーター(y)に受け取った値と、make_adder関数がパラメーター(x)に受け取った値を加算したものを戻り値とする。言葉で説明するよりは、実際に動作を見てもらった方がよいだろう。
one_adder = make_adder(1)
print(one_adder(100))
このコードでは、まずmake_adder関数の引数に「1」を指定して呼び出している。その結果がどうなるかを考えてみよう。
make_adder関数内ではパラメーターxの値が「1」となる。よって、adder関数の「return x + y」という部分は「return 1 + y」と読み替えられる。つまり、戻り値となる関数は次のようなものだ。
def adder(y):
return 1 + y
この関数が「make_adder関数の戻り値」となって変数one_adderに代入される(「one_adder」というのは「1を加算する関数」という意味)。そして、2行目では引数に「100」を指定してこの関数を呼び出している。ということは、実行結果は次のようになる。
ここまで「変数に関数を代入する」「関数を関数の引数にする」「関数を関数の戻り値にする」ことができるのを見てきた。このように「数値や文字列などと同様に関数を扱える」特徴のことを「関数は第一級オブジェクトである」などと表現することもある*1。また、関数を受け取る関数や、関数を戻り値とする関数のことを「高階関数」(high order functions)と呼ぶこともある。
*1 この場合の「第一級」とは「他のオブジェクト(数値や文字列などの基本データ型のオブジェクト)と同等の扱いが認められている」といった意味だと考えるとよいだろう。プログラミング言語の中には、変数に関数を代入したり、関数に関数を渡したり、関数を関数の戻り値にしたりといった操作ができないものもある。
Copyright© Digital Advantage Corp. All Rights Reserved.