-
Notifications
You must be signed in to change notification settings - Fork 0
Custom class method decorator
AndrewMZ edited this page Aug 8, 2022
·
7 revisions
How to make custom class method decorators
def classdecorator(method):
# method = MyClass.show_args <- it's a function, not method!
# OUTPUT:
print(f"method enclosing: {method}") # <function MyClass.show_args at 0x000001D83BD2EEF0>
print(f"method.__name__ enclosing: {method.__name__}") # show_args
print(f"method.__class__ enclosing: {method.__class__}") # <class 'function'>
print(f"enclosing dir: {dir()}") # ['method']
print(f"enclosing locals: {locals()}") # {'method': <function MyClass.show_args at 0x0000016BDE7FEEF0>}
def wrapper(something):
# something = self <- implicit frist argument
# OUTPUT:
print(f"something inner: {something}") # <__main__.MyClass object at 0x0000016BDE7DB910>
print(f"something.__class__ inner: {something.__class__}") # <class '__main__.MyClass'>
print(f"inner dir: {dir()}") # ['method', 'something']
print(f"inner locals: {locals()}") # {'something': <__main__.MyClass object at 0x0000016BDE7DB910>, \````
print('some additional functionality here') # 'method': <function MyClass.show_args at 0x0000016BDE7FEEF0>}
# this is what's happening here: MyClass.show_args(instance_name)
# we explicitly pass instance to a "function", which is the class method
method(something)
return wrapper
class MyClass:
def __init__(self, *args):
self.args = args
@classdecorator
def show_args(self):
print(self.args)
print(f"MyClass.show_args: {MyClass.show_args}")
m = MyClass(123)
m.show_args()
# show_args = classdecorator(show_args)
# console OUTPUT:
# method enclosing: <function MyClass.show_args at 0x000001D83BD2EEF0>
# method.__name__ enclosing: show_args
# method.__class__ enclosing: <class 'function'>
# enclosing dir: ['method']
# enclosing locals: {'method': <function MyClass.show_args at 0x000001D83BD2EEF0>}
# MyClass.show_args: <function classdecorator.<locals>.wrapper at 0x000001D83BD2F010>
# something inner: <__main__.MyClass object at 0x000001D83BD0B8B0>
# something.__class__ inner: <class '__main__.MyClass'>
# inner dir: ['method', 'something']
# inner locals: {'something': <__main__.MyClass object at 0x000001D83BD0B8B0>, 'method': <function MyClass.show_args at 0x000001D83BD2EEF0>}
# some additional functionality here
# (123,)
And by the nature of decorators the same result will be from this code
class MyClass:
def __init__(self, *args):
self.args = args
def show_args(self):
print(self.args)
show_args = classdecorator(show_args)
We can also create parametrized class method decorator!
def my_method_decorator(*params, **kwarams):
print(f"params, kwarams: {params}, {kwarams}")
def decorator(method):
def wrapper(self, *args, **kwargs):
print(f"do something using {params} and {kwarams}")
method(self, *args, **kwargs)
print("finish work")
return wrapper
return decorator
class MyClass:
def __init__(self, *args):
self.args = args
@my_method_decorator('something', 2, think='about')
def show_args(self):
print(f"self.args: {self.args}")
m = MyClass('class', 'args')
m.show_args()
# OUTPUT:
# ('something', 2) {'think': 'about'}
# do something using ('something', 2) and {'think': 'about'}
# self.args: ('class', 'args')
# finish work
