連載
» 2019年05月28日 05時00分 公開

Python入門:[Python入門]ローカル関数とラムダ式 (1/3)

Pythonでは、関数を変数に代入したり、関数の引数や戻り値に使用したりできる。この特性と、簡潔に関数を記述できるようにするラムダ式について見ていく。

[かわさきしんじ,Deep Insider編集部]
「Python入門」のインデックス

連載目次

 前回は、Pythonの関数におけるローカル変数の特徴をスタート地点として、変数のスコープや名前空間について見た。今回は関数をオブジェクトとして扱う方法、ローカル関数、ラムダ式といった高度な話題を取り上げる。

関数を変数に代入してみる

 Pythonでは「1」「0.1」のような数値も、'Python'のような文字列も「オブジェクト」である。この話自体は第3回「数値と算術演算」の「Pythonで計算してみよう」などでも話している。そして、Pythonでは「関数もオブジェクト」であり、変数に関数を代入したり、関数に引数として関数を渡したりといったことができる。文章だけではよく分からないので、ちょっと実際に試してみよう。

mylen = len  # 組み込みのlen関数を変数mylenに代入
print(mylen('Python'))  # 「mylen関数」を呼び出す

len関数に別名を付ける

 上のコードの1行目では、Pythonに組み込みのlen関数を変数mylenに代入している。このとき、関数呼び出し時に付加するかっこ「()」がないことに注意しよう(なお、「len」という名前は、前回に話した名前解決の過程を経て、ビルトイン名前空間にあるlen関数に解決される)。

 このように「関数を変数に代入」すると、今度は「代入した変数を使ってその関数を呼び出す」ことが可能になる。それを実際に行っているのが2行目のコードだ。このときには、かっこ「()」を付けてその中に引数を記述することで「関数を呼び出している」ことを明示する。

 実行結果を以下に示す。

mylen関数を呼び出した結果 mylen関数を呼び出した結果

 変数mylenにかっこと引数を付加して呼び出すことで、len関数と同じものが実行され、文字数が表示された。

 このことから、Pythonでは「変数に関数を代入できる」ことが分かる。このとき「len('Python')」のように元の名前で関数を呼び出すことももちろんできる。つまり、「len」と「mylen」という2つの名前は共に、コンピュータのメモリ上に存在する関数の実体(オブジェクト)を参照しているということだ。

「len」と「mylen」は同じ「オブジェクト」を参照している 「len」と「mylen」は同じ「オブジェクト」を参照している

 このように、Pythonでは関数も数値や文字列と同じように、変数に代入することが可能だ。さらに、「関数を引数に受け取る関数」や「関数を戻り値とする関数」もある。これらについても簡単に見てみよう。

関数を受け取る関数

 関数を引数に受け取る関数もある。組み込みのtype関数がその一つだ。type関数に引数を1つだけ渡すと、渡されたオブジェクトの型が返される。この関数にlen関数を渡してみよう。

print(type(len))

len関数の型を調べる

 実行結果は次のようになる。

len関数の型は「builtin_function_or_method」である len関数の型は「builtin_function_or_method」である

 「<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')

len関数と、それに渡す文字列'Python'を引数にしてapply関数を呼び出す

 上のコードでは、第1引数にはlen関数を、第2引数には文字列'Python'を指定しているので、apply関数の内部では「func(param)」は「len('Python')」となる。つまり、文字列'Python'の文字数がapply関数の戻り値となる。

apply関数を呼び出して、len関数を実行したところ apply関数を呼び出して、len関数を実行したところ

 このように数値や文字列などと同様に「関数を関数の引数」とすることも可能だ。ここまでに「変数に関数を代入する」「関数を関数の引数にする」ことができるのを見てきた。では、「関数を関数の戻り値にする」ことは可能だろうか。もちろん、可能だ。

関数を返す関数(ローカル関数の定義)

 関数を関数の戻り値にすることも可能だ。それには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関数を呼び出して、その戻り値(関数)を変数one_adderに代入し、それを呼び出すコード

 このコードでは、まずmake_adder関数の引数に「1」を指定して呼び出している。その結果がどうなるかを考えてみよう。

make_adder関数に引数「1」を指定した呼び出すとどうなるか make_adder関数に引数「1」を指定した呼び出すとどうなるか

 make_adder関数内ではパラメーターxの値が「1」となる。よって、adder関数の「return x + y」という部分は「return 1 + y」と読み替えられる。つまり、戻り値となる関数は次のようなものだ。

def adder(y):
    return 1 + y

make_adder関数に引数「1」を指定した呼び出したときに定義されるadder関数

 この関数が「make_adder関数の戻り値」となって変数one_adderに代入される(「one_adder」というのは「1を加算する関数」という意味)。そして、2行目では引数に「100」を指定してこの関数を呼び出している。ということは、実行結果は次のようになる。

引数に「100」を指定してone_adder関数を呼び出したので「101」と表示された 引数に「100」を指定してone_adder関数を呼び出したので「101」と表示された

 ここまで「変数に関数を代入する」「関数を関数の引数にする」「関数を関数の戻り値にする」ことができるのを見てきた。このように「数値や文字列などと同様に関数を扱える」特徴のことを「関数は第一級オブジェクトである」などと表現することもある*1。また、関数を受け取る関数や、関数を戻り値とする関数のことを「高階関数」(high order functions)と呼ぶこともある。

*1 この場合の「第一級」とは「他のオブジェクト(数値や文字列などの基本データ型のオブジェクト)と同等の扱いが認められている」といった意味だと考えるとよいだろう。プログラミング言語の中には、変数に関数を代入したり、関数に関数を渡したり、関数を関数の戻り値にしたりといった操作ができないものもある。


       1|2|3 次のページへ

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。