クロージャ(Closure)の仕組み
Pythonにおけるクロージャとは、外側のスコープで定義された変数を、内側の関数が保持し続ける仕組みを指します。外側の関数が実行を終えた後でも、内側の関数はその変数を参照し続けることができるため、状態を保持する関数を作成する際に非常に有効です。
クロージャを構成する3つの条件
- 関数の中にさらに関数が定義されている(入れ子構造)。
- 内側の関数が、外側の関数のスコープにある変数を利用している。
- 外側の関数が、内側の関数オブジェクトを戻り値として返している。
def power_factory(exponent):
# 外側のスコープの変数: exponent
def calculate_power(base):
# 内側の関数が外側の変数を参照
return base ** exponent
return calculate_power
# 二乗を計算するクロージャの生成
square = power_factory(2)
print(square(5)) # 出力: 25
# 三乗を計算するクロージャの生成
cube = power_factory(3)
print(cube(5)) # 出力: 125
nonlocalキーワードによる状態の更新
クロージャ内部で外側の変数を更新したい場合は、nonlocalキーワードを使用します。これにより、グローバル変数を使わずにデータのカプセル化が可能になります。
def create_accumulator(initial_value=0):
current_sum = initial_value
def add(value):
nonlocal current_sum
current_sum += value
return current_sum
return add
acc = create_accumulator(10)
print(acc(5)) # 15
print(acc(20)) # 35
デコレータ(Decorator)の基本と応用
デコレータは、既存の関数やメソッドの定義を変更することなく、機能を追加したり拡張したりするための仕組みです。実体は、関数を引数として受け取り、新しい関数を返す「高階関数」です。ログ出力、認証チェック、実行時間の計測などに頻繁に利用されます。
基本的なデコレータの構造
デコレータを適用するには、@デコレータ名というシンタックスシュガーを使用します。
def simple_logger(func):
def wrapper(*args, **kwargs):
print(f"--- {func.__name__} の実行開始 ---")
result = func(*args, **kwargs)
print(f"--- {func.__name__} の実行終了 ---")
return result
return wrapper
@simple_logger
def process_data(data):
print(f"データを処理中: {data}")
process_data("Sample text")
引数を持つデコレータ(デコレータファクトリ)
デコレータ自体に引数を渡したい場合は、さらにもう一層関数を重ねる「デコレータファクトリ」を作成します。
def access_control(role):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"アクセス権限を確認中: {role}")
if role != "admin":
return "アクセス拒否: 権限が不足しています"
return func(*args, **kwargs)
return wrapper
return decorator
@access_control(role="user")
def delete_database():
return "データベースを削除しました"
print(delete_database()) # アクセス拒否メッセージが表示される
複数のデコレータを重ねる
一つの関数に複数のデコレータを適用することも可能です。この場合、上から順番に適用されます。
def bold(func):
def wrapper():
return f"<b>{func()}</b>"
return wrapper
def italic(func):
def wrapper():
return f"<i>{func()}</i>"
return wrapper
@bold
@italic
def get_text():
return "Hello Python"
print(get_text()) # <b><i>Hello Python</i></b>
クラスデコレータ
デコレータは関数だけでなく、クラスに対しても適用できます。クラスのメタデータを変更したり、新しいメソッドを動的に追加したりする際に利用します。
def add_version(cls):
cls.version = "1.0.0"
def get_version(self):
return self.version
cls.get_version = get_version
return cls
@add_version
class Application:
def __init__(self, name):
self.name = name
app = Application("Task Manager")
print(app.version) # 1.0.0
print(app.get_version()) # 1.0.0