Skip to content

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
Clone this wiki locally