fromfunctoolsimportupdate_wrapperclassdecorate_function:"""Decorator for function"""def__init__(self,func):self.func=funcupdate_wrapper(self,self.func)def__call__(self,*args,**kwargs):print(f"Decorated by {self.__class__.__name__}")returnself.func(*args,**kwargs)
fromfunctoolsimportwrapsclassdecorate_method:"""Decorator for method"""def__init__(self,method):ifnotcallable(method)andnothasattr(method,"__get__"):raiseTypeError(f"{method!r} is not callable or a descriptor")self.method=methoddef__get__(self,obj,cls=None):print(f"decorate_method.__get__ is called from {obj}")ifobjisNone:returnselfprint(f"decorate_method.__get__ create wrapper for {obj}")@wraps(self.method)defwrapper(*args,**kwargs):print(f"Decorated by {self.__class__.__name__}")returnself.method.__get__(obj,cls)(*args,**kwargs)returnwrapper
$ python sample.py
=== call a.method("one")decorate_method.__get__ is called from <__main__.Sample object at 0x7f7fabcfd570>
decorate_method.__get__ create wrapper for <__main__.Sample object at 0x7f7fabcfd570>
Decorated by decorate_method
self.value: A, arg: one=== call b.method("one")decorate_method.__get__ is called from <__main__.Sample object at 0x7f7fabccb430>
decorate_method.__get__ create wrapper for <__main__.Sample object at 0x7f7fabccb430>
Decorated by decorate_method
self.value: B, arg: one=== call a.method("two")decorate_method.__get__ is called from <__main__.Sample object at 0x7f7fabcfd570>
decorate_method.__get__ create wrapper for <__main__.Sample object at 0x7f7fabcfd570>
Decorated by decorate_method
self.value: A, arg: two
fromfunctoolsimportwrapsfromweakrefimportWeakKeyDictionaryclassdecorate_method_memoize:"""Decorator for method, memoize version"""def__init__(self,method):ifnotcallable(method)andnothasattr(method,"__get__"):raiseTypeError(f"{method!r} is not callable or a descriptor")self.method=methodself.cache=WeakKeyDictionary()def__get__(self,obj,cls=None):print(f"decorate_method_memoize.__get__ is called from {obj}")ifobjisNone:returnselfif(wrapper:=self.cache.get(obj,None))isnotNone:returnwrapperprint(f"decorate_method_memoize.__get__ create wrapper for {obj}")@wraps(self.method)def_wrapper(*args,**kwargs):print(f"Decorated by {self.__class__.__name__}")returnself.method.__get__(obj,cls)(*args,**kwargs)self.cache[obj]=_wrapperreturn_wrapper
$ python sample.py
=== call a.method("one")decorate_method_memoize.__get__ is called from <__main__.Sample object at 0x7f2d61cb7430>
decorate_method_memoize.__get__ create wrapper for <__main__.Sample object at 0x7f2d61cb7430>
Decorated by decorate_method_memoize
self.value: A, arg: one=== call b.method("one")decorate_method_memoize.__get__ is called from <__main__.Sample object at 0x7f2d61cb6350>
decorate_method_memoize.__get__ create wrapper for <__main__.Sample object at 0x7f2d61cb6350>
Decorated by decorate_method_memoize
self.value: B, arg: one=== call a.method("two")decorate_method_memoize.__get__ is called from <__main__.Sample object at 0x7f2d61cb7430>
Decorated by decorate_method_memoize
self.value: A, arg: two