Phython

【Python】関数内関数とクロージャ―の使い方

本記事では、pythonにおける関数内関数とクロージャ―の使い方について説明していこうと思います。

関数内関数も、クロージャ―もどちらもpythonを学習するうえで非常に重要な文法になっているのでぜひ最後まで見ていってください。

ちなみに、本ブログでは初心者の方でも理解できるように丁寧に説明しているので、全くの初心者という方も安心してください。

また、pythonをまだインストールしていないといった方は以下の記事を参考にしてインストールしてみましょう。

この記事でわかること

  • 関数内関数の使い方
  • 関数内関数を使用するメリット
  • クロージャ―の使い方
  • クロージャ―を使用するメリット

 関数内関数について

まず初めに、関数内関数とはどのようなものなのかについて説明していこうと思います。

また、今回は関数に関する話がメインになると思うので「pythonでの関数の使い方がよくわからない」といった方は以下の記事を参考にしてみてください。

関数内関数とは?

関数内関数とは、その言葉の通りある関数内で宣言された関数のことです。

基本的な構文は以下の通りになります。

def 外側の関数():
    def 内側の関数()
        内側の関数の処理
    外側の関数の処理

少し関数内が複雑になるため、インデントに気を付ける必要がありますね。
また、関数内関数の特徴として、内側の関数は外側の関数内でしか使用することが出来ないので注意しましょう。

では、実際のコードを用いて使い方を確認していきます。

関数内関数の使い方

<input>

def mainfunction(a, b):

    def subfunction(c, d):
        return c + d

    print(subfunction(a, b))


mainfunction(2, 4)

<output>

6

では、コードを用いて使い方の説明をしていこうと思います。

まず、上記コードでは外側の関数として『mainfunction』を、内側の関数(関数内関数)として『subfunction』を使用していますね。
『subfunction』の中身は、<input>の4行目に書いてあり、『二つの引数を足す』といった内容になっています。

今回は、mainfunctionの引数として2と4が与えられているため、mainfunctionのaに2を、bに4を代入して関数の中での処理を見ていきます。

mainfunction内の処理はいたってシンプルで、まず最初の二行で内側の関数を定義したのち、その下の文で内側の関数を用いて計算結果を出力しています。

今回は、『a = 2, b = 4』だったので、関数『subfunction』にそれらの値を代入すると、答えは『6』になりますね。
なので最終的に6が出力されるような形になっています。

関数内関数を使用するメリット

関数内関数を使用するメリットは、コードが読みやすくなることです。
例えば、以下の二つの状況を考えてみましょう。

ここで、登場する関数には以下のような特徴があるとします。
※関数Bの機能は関数Aの中、関数Dの機能は関数Cの中でしか使用しない。

<関数内関数を使用しない場合>

関数A():
    関数Aに関する処理
関数B():
    関数Bに関する処理
関数C():
    関数Cに関する処理
関数D():
    関数Dに関する処理

<関数内関数を使用する場合>

関数A():
    関数B():
        関数Bに関する処理
    関数Aに関する処理
関数C():
    関数D():
        関数Dに関する処理
    関数Cに関する処理

この二つのコード、どちらを実行しても同じ結果が得られるのですが、下のコードの方が関数が二つにまとめられていてコードが読みやすいのがわかるかと思います。

結局、関数Bや関数Dは関数Aや関数Cの中でしか使わないんだから、外に出しておく必要はないといった感じですね。

 クロージャ―について

続いて、クロージャ―について使い方や使用するメリットを説明していこうと思います。
関数内関数の知識を必要とするのでセットで覚えてしまいましょう。

クロージャ―とは?

まず初めにクロージャ―の基本構文を紹介していこうと思います。

# 関数の定義方法
def 外側の関数(引数A)
    def 内側の関数()
        内側の関数の処理(引数Aを使用)
    return 内側の関数

# 呼び出し方法
f = 外側の関数(引数A)
print(f())

このような形です。
ちなみに、この時の内側の関数のことをクロージャ―と呼んだりしています。

これのみだと文字ばかりでわかりにくいと思うので、以下で実際のコードを見て理解を深めていきましょう。

クロージャ―の使い方

<input>

def mainfunction(a, b):
    def subfunction():
        return a + b
    return subfunction

f = mainfunction(1, 2)
print(f())

<output>

3

それでは、上記のコードについて詳しく説明していこうと思います。

まず、関数『mainfunction』ですが、内側に別の関数『subfunction』が宣言されており、こちらは二つの数を足し算するような関数になっています。
ちなみに、この『subfunction』が今回のコードのクロージャ―に当たります。
また、関数『mainfunction』では、戻り値が『subfunction』というクロージャ―になっています。
ここで注意してほしいのが、『subfunction』の後ろに()がついていないことです。

通常、関数は後ろに()をつけることで実行するのですが、『mainfunction』の戻り値には()がついていないため、『実行手前のsubfunction』が戻り値であると考えてください。

なので、『print(mainfunction(1, 2)』といった風にprint文を書いても適切な値は返ってきません。
なぜなら、先ほども述べたようにmainfunctionの戻り値が実行手前のsubfunctionだからです。
実行手前のsubfunctionが出力されたって誰も嬉しくありません。

なので、変数fに実行手前のsubfunctionが入った『mainfunction(1, 2)』を渡して、その変数を()をつけることによって実行することで正しい結果が得られるようになります。

クロージャ―を使用するメリット

クロージャ―を使用するメリットは、ある状態を保持したまま別の処理を実行できるといった点にあります。
こちらも少しわかりにくいと思いますので、実際のコードを用いてクロージャ―の有用性を確認していきましょう。

<input>

def circle_area(pi):

    def cal(radius):
        return pi * radius * radius

    return cal


x1 = circle_area(3)
x2 = circle_area(3.14)
x3 = circle_area(3.14159265)

print(x1(5))
print(x2(5))
print(x3(5))

<output>

75
78.5
78.53981625

上記のコードは、円の面積を計算するといったものです。
x1~x3にそれぞれpiの値を入れておくことで、異なる円周率での面積の計算が好きな時に行えるようになりました。

このように、外側の関数の引数を覚えて、好きな時に実行することが出来るというのがクロージャ―のメリットになります。

 まとめ

今回は、関数内関数やクロージャ―について基本的な使い方と使用するメリットを紹介してきましたが、いかがだったでしょうか。

関数内関数やクロージャ―はどちらも複雑なので初めて見る方は理解に苦しむと思いますが、自分で実際に関数内関数・クロージャ―を使用したコードを作成してみて徐々に理解を深めてみてください。

-Phython
-, ,