クロージャと自由変数
内部関数で状態を捕捉します
「クロージャと自由変数」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。
ネストした関数
Pythonでは、ある関数の内部に別の関数を定義できます。内側の関数は、外側の関数が実行されるたびに新しく作成されます。
def outer():
def inner():
return 'from inner'
return inner()
print(outer())内側の関数から外側の変数を参照する
内側の関数は、外側の関数で定義された変数を読み取れます。これらは内側の関数のローカル変数ではないため、自由変数と呼ばれます。
def outer():
message = 'hello'
def inner():
return message
return inner()
print(outer())クロージャとは何ですか?
クロージャとは、内側の関数が返された後も、外側のスコープにある自由変数を記憶している仕組みです。外側のスコープの処理が終了した後でも、その変数を参照できます。
def make_greeter(name):
def greet():
return 'Hi ' + name
return greet
g = make_greeter('Ada')
print(g())キャプチャした状態は保持される
外側の関数はすでに戻っていますが、クロージャはnameを保持しています。値は、返された関数の内部で存続します。
def make_greeter(name):
def greet():
return 'Hi ' + name
return greet
a = make_greeter('Ada')
b = make_greeter('Bob')
print(a())
print(b())乗算器ファクトリ
クロージャは、カスタマイズした関数を生成するファクトリとして力を発揮します。ここでは、返される各関数がキャプチャした係数を使って乗算します。
def multiplier(factor):
def multiply(n):
return n * factor
return multiply
double = multiplier(2)
triple = multiplier(3)
print(double(10))
print(triple(10))各クロージャは独立している
ファクトリを呼び出すたびに、独自の値をキャプチャした別々のクロージャが作成されます。互いに影響を与えることはありません。
def adder(amount):
def add(n):
return n + amount
return add
add5 = adder(5)
add100 = adder(100)
print(add5(1), add100(1))クロージャが保持する値を調べる
キャプチャされた名前は__code__.co_freevarsに一覧表示され、その値は__closure__のセルに格納されています。
def make(x):
def f():
return x
return f
fn = make(42)
print(fn.__code__.co_freevars)
print(fn.__closure__[0].cell_contents)クロージャがキャプチャするのは値ではなく変数
クロージャがキャプチャするのは変数そのものなので、変数の最後の値を参照します。これは、クロージャの作成後に変数が変更される場合に重要です。
def build():
x = 1
def show():
return x
x = 99
return show
print(build()())遅延バインディングによるループの落とし穴
よくある落とし穴として、ループ内で作成されたクロージャはすべて同じループ変数を共有するため、その最後の値をキャプチャします。
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs])遅延バインディングを修正する
デフォルト引数を使って現在の値を束縛すると、各クロージャは定義時にそれぞれの値のコピーをキャプチャします。
funcs = []
for i in range(3):
funcs.append(lambda i=i: i)
print([f() for f in funcs])軽量なオブジェクトとしてのクロージャ
クロージャはデータと振る舞いをまとめるため、小さなオブジェクトに似ています。単純なケースでは、完全なクラスよりもすっきりした実装になることがよくあります。
def counter_start(start):
def value():
return start
return value
c = counter_start(10)
print(c())クイックチェック
Pythonにおけるクロージャとは何ですか?
復習:クロージャと自由変数
重要なポイント:
- 内側の関数は、外側のスコープにある変数(自由変数)を読み取れます。
- クロージャとは、それらの変数を記憶する、返された内側の関数です。
- ファクトリを呼び出すたびに、独立したクロージャが作成されます。
- クロージャがキャプチャするのは値ではなく変数なので、遅延バインディングによるループの落とし穴が生じます。デフォルト引数で修正できます。
def power_of(exp):
return lambda base: base ** exp
square = power_of(2)
print(square(9))よくある質問
「クロージャと自由変数」レッスンは無料ですか?
はい。「クロージャと自由変数」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。
「クロージャと自由変数」で何を学びますか?
内部関数で状態を捕捉します ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Python Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「クロージャと自由変数」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPython Academyレッスンでコードを書いて実行できますか?
はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 第一級関数
- クロージャと自由変数
- nonlocalと可変状態
- 部分関数