おぼえがき

過ちては則ち改むるにうんぬんかんぬん

クロージャ―について(Python)

f:id:feci:20210726231508j:plain

Python3

 

Python3.8.5でのクロージャ―について。

#①クロージャ―のパターンA
def aaa(ab):
  def bbb():
    return a + b

  return bbb

r = aaa(12)
r1 = r()

print(r() , r1)
print(r)        #まだ関数bbbが実行されてないので0x000001A8EF74DF70と表示される


#②クロージャ―のパターンB
def aaa(a):
  def bbb(b):
    return a + b + b

  return bbb

r0 = aaa(1)
r1 = aaa(5)

print(r0(10) , r1(5)) #ここでbの値を指定している

クロージャ―とは、インナー関数の返り値を関数実行後の値ではなく実行前の関数そのものとして返す処理(?)のことです。

 

 

上記のプログラムの出力結果は、それぞれ以下のようになります。

 

①の出力結果

3 3

 

②の出力結果

21 15

 

 

①の出力結果は、インナー関数をすでに理解していればあるていど理解しやすいと思います。

 

まず、インナー関数bbbの返り値を入れる変数が関数内に指定されていません(def bbb():)。

そして関数aaaの最終的な返り値は関数bbbとなっており、bbb処理後の値を返すようには指定されていません(return bbb)。

 

この結果、関数aaaの返り値を受ける変数rには、まだ実行されていない関数bbbが直接入っている状態となります。

もしこの状態で変数rをprintしてやると、0x000001A8EF74DF70 というよく分からない文字列がでてきます。

 

しかし r() と記述して変数rに格納されている関数bbbを実行してやると、bbbの処理結果である3が返ってきます。

 

 

②のパターンでは、インナー関数bbbの返り値を入れる変数bが関数内に指定されていますが、returnの値は関数bbbそのものとなっています。

さらに、変数aの引数はr0またはr1でそれぞれ指定していますが、変数bの引数が現時点では指定されていません。

 

このようなパターンでは、①のようにただ単に r0() や r1() を記述(r0およびr1を実行)するだけでは、a+b+bという意図した値は返ってきません。

このパターンでは、r0またはr1の実行時に()の中に変数bの引数を指定しなければいけません。

 

ということで、②の出力結果ではr0(10)だと1+10+10=21となりますし、r1(5)は5+5+5=15となるわけです。

 

このような処理の流れ(記述法?)を、Pythonではクロージャ―と呼びます。

 

 

以上です。