Pythonクロージャ解説:ネスト関数が変数を捕捉する仕組み
Pythonクロージャ
Pythonクロージャの仕組み、定義方法、クリーンで効率的なコードに不可欠な理由を学びます。
ネスト関数におけるnonlocal変数
クロージャを探る前に、ネスト関数とnonlocal変数の理解が不可欠です。別の関数内部で定義された関数をネスト関数と呼びます。このような関数は外側スコープの変数を読み取れます。
Pythonではこれらnon-local変数はデフォルトで読み取り専用です。変更するにはネスト関数内でnonlocal宣言が必要です。
ネスト関数が外側スコープ変数にアクセスする簡単な例:
def print_msg(msg):
# 外側関数
def printer():
# ネスト関数
print(msg)
printer() # 実行
print_msg("Hello")
出力
Hello
ネスト関数printer()が外側スコープのmsg変数にアクセスできています。
クロージャ関数の定義
外側関数がネスト関数を呼び出す代わりに返したらどうなるか?コードはこうなります:
def print_msg(msg):
def printer():
print(msg)
return printer # ネスト関数を返す
# 返された関数を保存
another = print_msg("Hello")
another()
出力
Hello
print_msgが実行終了後も、関数printerはmsgの値を覚えています。この現象—関数が定義スコープの変数へのアクセスを保持すること—をPythonではクロージャと呼びます。
さらに説明のため、元関数を削除しても返された関数が動作することを確認:
>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
... NameError: name 'print_msg' is not defined
返された関数はクロージャに必要なデータを捕捉したため機能し続けます。
クロージャが存在する条件
Pythonでは、ネスト関数が以下を満たすときクロージャが存在します:
- 別の関数内部で定義されている。
- 外側関数の変数を参照している。
- 外側関数によって返される。
クロージャを使うべき場面
クロージャにはいくつかの利点があります:
- グローバル変数の必要性を排除し、カプセル化を強化。
- 単一メソッドクラスの軽量代替となり、コードを簡潔に保つ。
- デコレータなどの関数型パターンを可能にし、ラッパー関数が元関数の引数にアクセスできるようにする。
一般的な例:乗算関数を生成するファクトリ。
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# 特定の乗算関数作成
times3 = make_multiplier_of(3)
times5 = make_multiplier_of(5)
print(times3(9)) # 27
print(times5(3)) # 15
print(times5(times3(2))) # 30
出力
27 15 30
Pythonのデコレータ構文はクロージャに大きく依存します。デコレータを書くとき、ラッパー関数がデコレート対象関数を捕捉し、クロージャを形成します。
クロージャを検査するには__closure__属性を使用。捕捉値を保持するセルオブジェクトのタプルを返します。例:
>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
各セルのcell_contents属性がクロージャで捕捉された実際の値を保持:
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5
クロージャ理解により、不要なグローバルを避け、関数型パラダイムを取り入れたよりクリーンでモジュラーなPythonコードが書けます。
Python
- Python データ型マスター: 実践ガイド
- Python 演算子完全マスター: 包括的ガイド
- Python pass文完全マスター: 実践ガイド
- Python ラムダ関数: 無名関数の実践ガイド
- Python辞書完全ガイド:作成、操作、高度なテクニック
- Pythonジェネレータ:効率的イテレーションと高度なユースケース
- Pythonデコレータマスター:エキスパート技法で関数を拡張
- Python strip()メソッド完全ガイド:実践例付き
- Pythonラムダ関数をマスターする:実例とベストプラクティス
- Python abs()関数:数値と複素数の絶対値を計算
- Python round()関数を実例で徹底解説