概要
注意:PythonのDecoratorとDecoratorパターンは別物。PythonのDecoratorは言語の機能であるのに対し、Decoratorパターンはどの言語でも実装可能である。Decoratorの機能の存在を考えると、PythonでDecoratorパターンを実装する理由が見つからない。
Decoratorパターンの主な目的は、オブジェクトに動作や属性を追加するために、継承に代わる、より柔軟な方法を可能にすること。従来の実装では、オブジェクトを再帰的に自身の型の子でラップする(これにより、メソッドコールをラップしたり、関数コールの前後に振る舞いを追加する)。
- 継承を避けるのではなく、一貫したインターフェイスを維持するために継承を利用する。そのため、内部状態やアイデンティティの管理が非常に複雑になる。
- ラップされたオブジェクトのメソッドを呼び出すために、Decoratorクラスは、ラップされたクラスのすべてのメソッドを実装する必要がある。
以下の実装例では、 Decorator機能を使ってこの欠点を克服しようとする。
validate_inputs デコレータはクラス全体をラップし、特定のメソッド(ここでは’input_’で始まるもの)のみをデコレーションする。このデコレータには、対象となるメソッドのデコレータとして設定された関数のリストが渡される。また、メソッドに設定されたデコレータの順序も維持される。この関数は、前述のような欠点がなく、多重継承に代わるより柔軟な手法として使用できる。
実装例
def validate_inputs(decorators):
def decorate(cls):
for method in dir(cls):
if callable(getattr(cls, method)) and method.startswith("input_"):
for decorator in reversed(decorators):
setattr(cls, method, decorator(getattr(cls, method)))
return cls
return decorate
def is_string(func):
def wrapper(self, text):
if type(text) is not str:
return "'{}' is invalid. ".format(text)
return func(self, text)
return wrapper
def is_lowercase(func):
def wrapper(self, text):
if not text.islower():
return "'{}' is invalid. ".format(text)
return func(self, text)
return wrapper
@validate_inputs([is_string, is_lowercase])
class Form():
def input_name(self, name):
return "'{}' is valid.".format(name)
if __name__ == "__main__":
form = Form()
print(form.input_name("TestName"))
print(form.input_name("testname"))
print(form.input_name(42))