Pythonのデコレーターでメタプログラミング 【第3回】【動的に装飾】 #7
どうも hrkblog です.
久しぶりの更新になってしまった....
今回はデコレーターの最終回です.
デコレータで動的にデコレートしていきます.
早速コードを見ていきます..!!
# plus_arg() is injected into Foo def plus_arg(self, a, b): return a + b # minus_arg() is injected into Foo def minus_arg(self, a, b): return a - b def change_methods(new): if new.__name__ != '__new__': return new def __new__(cls, *args, **kws): # Add attributes cls.plus_arg = plus_arg cls.minus_arg = minus_arg # Delete attributes if hasattr(cls, 'say'): del cls.say return super(cls.__class__, cls).__new__(cls, *args, **kws) return __new__ class Foo(object): @change_methods def __new__(): pass def say(self): print("Hi me:", self) def main(): foo = Foo() print('plus_arg : {}\nminus_arg : {}'.format(foo.plus_arg(1, 3), foo.minus_arg(1, 3))) try: print(foo.say()) except AttributeError as ex: print('method say() has already been deleted.') print(ex) if __name__ == '__main__': main()
まずは、mainから.
foo = Foo() print('plus_arg : {}\nminus_arg : {}'.format(foo.plus_arg(1, 3), foo.minus_arg(1, 3))) try: print(foo.say()) except AttributeError as ex: print('method say() has already been deleted.') print(ex)
Fooのインスタンス生成 -> fooのplus_arg(1, 3)とfooのminus_arg(1, 3)を呼び出して
結果をそれぞれ出力してみてます.
そのあとfooのsay()メソッドを呼び出してプリントしてます.
そしてsay()がなければ'method say() has already been deleted'のメッセージをプリントすることにします.
ここだけだとなんのこっちゃて感じですね.
引数を足したり引いたりする単純なplus_arg()とminus_arg()が今回Fooに付け足すメソッドです.
# plus_arg() is injected into Foo def plus_arg(self, a, b): return a + b # minus_arg() is injected into Foo def minus_arg(self, a, b): return a - b
クラスFooをみてみます.
class Foo: @change_methods def __new__(): pass def say(self): print("Hi me:", self)
Fooは__new__
にデコレーターをつけてます.
そして単純な出力をするメソッドsay()があります.
このいかにもな@change_methods
をみてみます.
def change_methods(new): if new.__name__ != '__new__': return new def __new__(cls, *args, **kws): # Add attributes cls.plus_arg = plus_arg cls.minus_arg = minus_arg # Delete attributes if hasattr(cls, 'say'): del cls.say return super(cls.__class__, cls).__new__(cls, *args, **kws) return __new__
普通のデコレーターですね.
引数の関数の名前が__new__
ではないならそのままその返すようにしてます.
__new__
だった場合は新しい__new__
をあげるようにします.(new __new__
じゃん...)
このnew __new__
はクラスにplus_argとminus_argというattributeを付け足してます.
(__new__
はインスタンス生成時__init__
の前に呼ばれます.)
そしてクラスにsayという属性があれば削除してしまいます.
実行結果は以下です.
plus_arg : 4 minus_arg : -2 method say() has already been deleted. 'Foo' object has no attribute 'say'
意外と簡単でしたね....?
いろんな使い道がありそうですが、
メタプログラミングってコードがカオスになりがちなんですよねw
(前に参画していた苦い記憶が蘇ってきたので今日はこの辺で......w)
今度はSpring Bootの記事でも書こうかなと思っていたり.....
Javaのブロックチェーンの記事とかも書きたい.....
今回3部作にして思ったのは1回目を書くと続き書かなきゃ...となるんですが、
ちょっと日が経つと重荷になってじゃっかんめんどくさくなる...
なので次はその時書きたい記事にしたいと思います....
それではまた次回にお会いしましょう~~~~~~