Blog Post

Python デコレータ 発展編


作成日 2023-02-11

目次

概要

前回は decorator とは何かについて説明しました。

本記事では Python デコレータでできることについていくつか紹介します。

ネスト

デコレートした関数に対して重複して使用することができます。
たとえば、以下のようにデコレータを定義したとします。

def print_once(func):
    def once_wrapper(*args, **kwargs):
        print("once")
        return func(*args, **kwargs)
    return once_wrapper

def print_twice(func):
    def twice_wrapper(*args, **kwargs):
        print("twice")
        print("twice")
        return func(*args, **kwargs)
    return twice_wrapper

@print_once
@print_twice
def run():
    print("hello")

実行すると以下のようになります。

>> run() 
once
twice
twice
hello

class系デコレータ

class デコレータも作ることもできます。
実行回数等何かしらのプロパティを管理したい時に使えます。

class CallDecorator:
    def __init__(self, func):
        self.call_time = 0
        self.func = func
    def __call__(self, *args, **kwargs):
        print(f"called {self.call_time} times")
        self.call_time += 1
        return self.func(*args, **kwargs)

@CallDecorator
def run():
    print("hello")

実行すると以下の通りです。

>> run()
called 0 times
hello
>> run()
called 1 times
hello

引数付デコレータ

引数付のデコレータを作ることもできます。
ただし、デコレータを2重で作成する必要があります。

def say(something):
    def decorator_func(func):
        def wrapper_func(*args, **kwargs):
            print(f"i will say {something}")
            return func(*args, **kwargs)
        return wrapper_func
    return decorator_func

@say("greetings!")
def run():
    print("hello")

実行すると以下の通りです。

>> run()
i will say greetings!
hello

まとめ

今回デコレータで他にできることについていくつか紹介しました。
次回は functools 等について紹介していきたいと思います。