【Python】関数内関数の使い方【入門第51回】

166, 2019-09-11

目次

関数内関数とは?

こんにちは、narupoです。

今回はPythonで関数内関数を使う方法を解説していきたいと思います。
関数内関数とは、じつは私の造語です。
これは、関数の中に書かれている関数のことを指します
関数内関数は、関数内でちょっとしたツールを書きたい時などに重宝します。

この記事では具体的には↓を見ていきます。

  • 関数内関数の書き方

  • 関数内関数の使い道

関数内関数の書き方

関数内関数なんて漢字がやたら並んでいますが、その内容は簡単です。
それは関数は、関数の中にも作ることができるということです。

たとえば関数は↓のように書きます。

def love():
    print('愛と')

love()

↑のコードの実行結果は「愛と」になります。
この関数loveの中にさらに関数を書くとたとえば↓のようになります。

def love():
    print('愛と')

    def peace():
        print('平和を!')

love()

↑の関数peaceは関数loveの中に書かれています。
このpeaceloveの中から呼ぶことができます。
たとえば↓のようにです。

def love():
    print('愛と')

    def peace():
        print('平和を!')

    peace() # ←ここで呼んでる

love()

↑のコードの実行結果は↓のようになります。

愛と
平和を!

まず関数loveが呼び出されます。
そしてprint('愛を')が実行されて、関数peaceが定義されます。
そのあとにloveの中でpeaceが呼び出されprint('平和を!')が実行されます。

関数peaceは関数loveの中以外では呼び出すことが出来ません。
たとえば↓のようにpeaceを呼び出そうとすると、

def love():
    def peace():
        print('平和を!')

peace()

↓のようなエラーになります。

Traceback (most recent call last):
  File ".\sample.py", line 5, in <module>
    peace()
NameError: name 'peace' is not defined

NameError: name 'peace' is not defined」は日本語にすると「名前エラー: 'peace'は未定義です
という意味になります。
未定義、つまり「作られていないよ」という意味ですね。
作られていない変数や関数にアクセスするとこのようなエラーになります。

関数内関数の使い道

この関数内関数は、なかなか便利な機能です。
関数で込み入った処理を書いていて、なにか便利なツールが欲しいな~という時にこの関数内関数が使えます。
たとえば↓のような関数があるとします。

def sum_of_list(lst):
    sm = 0
    for el in lst:
        sm += el
    return sm

result = sum_of_list([1, 2, 3])
print(result)

関数sum_of_listはリストの要素の値の合計を計算する関数です。
↑のコードの実行結果は↓のようになります。

6

このsum_of_listは、リストの要素にアクセスしていますが、リストの要素が数値とは限りません。
要素が加算できるオブジェクトかどうか判定したほうがよさそうです。
そこで、関数内関数を使うと、↓のように書くことができます。

def sum_of_list(lst):
    def safe_add(x):
        if not isinstance(x, (int, float)):
            return 0
        return x

    sm = 0
    for el in lst:
        sm += safe_add(el)
    return sm

result = sum_of_list([1, 2, None, 3.5, '( ^_^ )'])
print(result)

safe_addという関数内関数を書きました。
これは引数xintfloatでないなら0を返す関数です。
そしてfor文の中でこのsafe_addを使って合計値を計算しています。
↑のコードの実行結果は↓のようになります。

6.5

for文の中で要素がintfloatかを判定するコードを書くと↓のようになります。

def sum_of_list(lst):
    sm = 0
    for el in lst:
        if isinstance(el, (int, float)):
            sm += el
    return sm

result = sum_of_list([1, 2, None, 3.5, '( ^_^ )'])
print(result)

注目してほしいのはfor文の中のインデントの深さです。
関数内関数を使った場合は、使っていない場合に比べてインデントの深さが1段浅くなっているのがわかります。
一般的に、インデントは深くなればなるほどコードの可読性が下がります。

そういった意味では前者の関数内関数を使ったコードのほうが読みやすいと言うべきなのですが、まぁ正直このケースは好みの問題と言えそうです。

おい

ここまで小規模の関数では↑のような結果になりがちですが、これが少し長い関数になると効果が全く違ってきます。
特に関数内関数を何度も使用するようなケースだと、確実に関数内関数を書いたほうが良いと言えます。

おわりに

関数内関数はクロージャ―の理解に不可欠な概念です。
そして実際に便利な機能でもあります。
ちょっとしたツールを書きたくなったら関数内関数の存在を思い出してみましょう。
もっとも、その場合も普通の関数として書くべきか、それとも関数内関数として書くべきかどうかを、ちゃんと一考したほうがいいでしょう。

以上、次回に続きます。

また見てね

関連動画

スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク