Pythonの高階関数とクロージャの仕組み

一、コード解説

def power(exponent):
    def inner(base):
        return base ** exponent
    return inner

この関数power高階関数で、別の関数innerを返します。コードを段階的に見ていきましょう:

1. power(exponent)は外部関数で、引数exponentを受け取ります。

2. power関数内で、別の関数inner(base)が定義されています。この関数は引数baseを受け取り、base ** exponentを返します。

3. 最も重要な行:return inner

この行では、内部で定義された関数innerを呼び出し元に返します。つまり、power関数が返すのは関数オブジェクトで、関数が定義されたときのスコープ内の変数exponentを覚えています。


二、クロージャの概念

クロージャ(Closure)は、関数がその定義時に存在していたスコープ内の変数を「覚えている」ものです。この変数は、関数が実行された後でも保持されます。

上記の例では: - power(2)が呼び出されると、inner関数オブジェクトが返され、変数squareに代入されます。 - power関数が実行されると、ローカル変数exponentは通常は破棄されるべきですが、inner関数がexponentを使っているため、Pythonexponentinnerの「環境」に保持し、クロージャが形成されます。 - そのため、power関数が終了した後でも、square(3)exponent = 2を使用して3 ** 2を計算できます。

これがクロージャです。


三、クロージャの実行過程を可視化

square = power(2)  # この時、exponent = 2が「記憶」される
print(square(3))   # 実際にはinner(3)が呼ばれ、3 ** 2 = 9が返される

他のクロージャを定義することもできます:

cube = power(3)
print(cube(2))   # 出力は8、2 ** 3 = 8だから

これにより、squarecubeは異なるクロージャ関数であり、それぞれ異なるexponent(2と3)を「記憶」していることが分かります。


四、クロージャの特徴まとめ

  1. クロージャは関数と、その定義時の環境変数が組み合わさったオブジェクトです。
  2. クロージャは、返された関数が作成された時のコンテキストを「記憶」します。
  3. クロージャは通常、ファクトリ関数を作成するために使われます。例えば、べき乗計算や線形変換などです。