Python Decorator
Python decorators
Section titled “Python decorators”:question_mark: Why we need decorator
:bulb: It will extend your function behaviors during runtime.
For example, you already have a function say_hi
def say_hi(name: str): return f"Hi! {name}"- function name
say_hi - parameter
nameand 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
def say_hi(name: str, my_name:str): return f"Hi! {name}. I'm {my_name}"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
def add_intro(my_name): def dec(func): def wrapper(name): return func(name) + f". I'm {my_name}" return wrapper return dec
@add_intro("Bob")def say_hi(name: str): return f"Hi! {name}":exclamation:Function signature is not changed and function behavior is enriched
How to create decorator
Section titled “How to create decorator”Decorator Function
Section titled “Decorator Function”Before starting decorator, we have to understand
- original function
- function name
- function parameters and types
- decorator function
- extra parameter
- new features
def hello(name:str) -> str: return f"hello, {name}"We have an original function
- function name:
hello- parameters:
name- types:
str
Now we can use these to build decorator function my_dec
def my_dec(func): def wrapper(name:str): return func(name) return wrapperExplanation:
line 1- decorator name :
my_dec - decorator parameter :
func(:warning: we did not use type hint here) - it mean
my_decwill decorate functionfunc
- decorator name :
line 2- inner function
wrapper(:warning: any function names) - inner function signature. It MUST be a superset of your original signature
e.g. only 1 parameter
nameathellothe wrapper function should includenameat least it could bewrapper(name),wrapper(name, name1=None),wrapper(name, *args, **kwargs)wrapper(*args, **kwargs)etc.- inner function
line 3return value
line 4- :exclamation: return a function name
wrapper
- :exclamation: return a function name
Now the decorator is working as func = my_dec(func)
- function IN :
func - function OUT:
wrapperand reassignedwrappertofunc
Decorator Class
Section titled “Decorator Class”class DecoratorClass: 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 return wrapper
@DecoratorClass(decorator_param="!!!")def hello_again(name: str): """original docStr""" return f"Hello {name}"it’s obviously to understand how to setup decorator’s parameters.
built-in python decorator
Section titled “built-in python decorator”Each function in python has metadata
__name____doc__
Either function or class cannot update decorator function metadata.
print(hello_again.__name__) # wrapper
print(hello_again.__doc__) # Wrapper Doc:question_mark: How to update function metadata
- manually update
class DecoratorClass1:def __init__(self, decorator_param: str):self.decorator_param = decorator_paramdef __call__(self, func):def wrapper(original_param):"""Wrapper Doc"""return func(original_param) + self.decorator_param# Manually update metadatawrapper.__doc__ = func.__doc__wrapper.__name__ = func.__name__return wrapper
- use python built-in
wrapper