Python decorators#
Why we need decorator
It will extend your function behaviors during runtime.
For example, you already have a function say_hi
- function name
say_hi
- parameter
name
and typestr
- one output
say_hi('Apple') => Hi! Apple
Next we plan to add one introduction to the output, such as Hi! Apple. I'm Bob
.
-
Modify your function
If this is only used once in our project, itβs manageable. However, modifying the function signature means that every instance of its use throughout the project must be updated, which is both tedious and time-consuming. -
Use decorator
Function signature is not changed and function behavior is enriched
How to create decorator#
Decorator Function#
Before starting decorator, we have to understand
- original function
- function name
- function parameters and types
- decorator function
- extra parameter
- new features
We have an original function
- function name:
hello
- parameters:
name
- types:
str
Now we can use these to build decorator function my_dec
Explanation:
line 1
- decorator name :
my_dec
- decorator parameter :
func
(we did not use type hint here)
- it mean
my_dec
will decorate functionfunc
- decorator name :
line 2
- inner function
wrapper
(any function names)
- inner function signature. It MUST be a superset of your original signature
e.g. only 1 parameter
name
athello
the wrapper function should includename
at least it could bewrapper(name)
,wrapper(name, name1=None)
,wrapper(name, *args, **kwargs)
wrapper(*args, **kwargs)
etc.
- inner function
line 3
return value
line 4
return a function name
wrapper
Now the decorator is working as func = my_dec(func)
- function IN :
func
- function OUT:
wrapper
and reassignedwrapper
tofunc
Decorator Class#
it's obviously to understand how to setup decorator's parameters.
built-in python decorator#
Each function in python
has metadata
__name__
__doc__
Either function
or class
cannot update decorator function metadata.
How to update function metadata
- manually update
class DecoratorClass1: def __init__(self, decorator_param: str): self.decorator_param = decorator_param def __call__(self, func): def wrapper(original_param): """Wrapper Doc""" return func(original_param) + self.decorator_param # Manually update metadata wrapper.__doc__ = func.__doc__ wrapper.__name__ = func.__name__ return wrapper
- use python built-in
wrapper