1.1.1. The simplest decoration behavior
One of the characteristics of decorator is to add content on the basis of executing original function.
Let's take a simple example:
We can use it as a log printer, and we will inform you politely before executing the function
"Dear coder, I'm going to execute it"
You will also be informed of the coder after execution.
Isn't it fun?
So, how do we execute the original function?
✔ if you give the name of the original function to the decoration function, the decoration function will have the ability to execute the old function.
Old function, function to be decorated
def fun(): print('I'm an old function') def factory(old_fun): print('='*20) old_fun() print('='*20) factory(fun)
1.1.2. Perfect decoration behavior
❓ what are the other problems with the decoration?
◇ the original function needs to be called through the decoration factory. The business department that originally called this function will modify the code in a large area;
❓ so how to improve this problem?
How to design a way to execute decoration factory when calling without changing the original function name.
◇ old_name = factory(old_name)
def fun(): print("I am fun") def factory(a): def tmp(): print("="*10) a() print("="*10) return tmp fun = factory(fun) fun()
1.1.3.python's decorator syntax sugar
old_name = factory(old_name) is the core statement for generating decorators. In order to avoid writing such brainless code every time, python provides a convenient way of writing, which we call the grammar sugar.
How to write grammar sugar:
·Find the function to decorate
·Write @, followed by the name of the decorator function br/>@decortate
def fun():
print('in fun() ...')
1.1.4. summary
The way to write decorator in python:
1. Define a mediation function named decoration behavior to receive a callable object
def get_timer(fn):
pass
2. Implement the decoration behavior function inside the intermediary function
def get_timer(fn):
def wrapper():
... (decoration code implementation)
3. Return the function name of decoration behavior at the end of mediation function:
def get_timer(fn):
def wrapper():
... (decoration code implementation)
return wrapperBr / > note: function name is returned instead of function call
4. Define @ decorator name before the function to be decorated
@get_timer
def fun():
pass
1.2. Several forms of Python decorator
1.2.1. Parameterless decorator
Demo1: add function when to run:
import time def time_fun(func): def my_time(): print(f" running at ") func() return my_time @time_fun def fun1(): print("+++++++++") fun1() time.sleep(2) fun1()
1.2.2. Decorated function has parameters
The core of decorator is that the behavior of internal function is renamed;
The form of internal function shall meet the form of original function;
import time def time_fun(func): def my_time(arg1): # Reserved interface in internal function print(f" running at ") func(arg1) # Original function transfer parameter return my_time @time_fun def fun1(arg1): print("+++++{}++++".format(arg1)) fun1(10) time.sleep(2) fun1(10)
1.2.3. The decorated function has indefinite parameters and return values
The original function has a return value, and the interior decoration function also receives the return value for return.
import time
def time_fun(func): def my_time(*args, **kwargs): print(f" running at ") func(*args, **kwargs) return my_time @time_fun def fun1(arg1, arg2, name): print("+++++{},{},{}++++".format(arg1, arg2, name)) fun1(10, 20, name='rocky') time.sleep(2) fun1(10, 20, name='jim')
1.2.4. Change the behavior of the decorator (pass parameters to the decorator)
In decorators, we also have a requirement. According to the different parameters passed in, the behavior of decorators will be different, so how to define this kind of decorator.
First, understand the syntax of decorators:
@time_fun def fun1(arg1, arg2, name): print("+++++{},{},{}++++".format(arg1, arg2, name)) //Name of raw material = name of decorator (name of raw material) @time_fun("itsource") def fun1(arg1, arg2, name): print("+++++{},{},{}++++".format(arg1, arg2, name)) fun1 = time_fun("itsource")(fun1)
In this way, it is necessary to ensure that the content returned by time Fu ("its source") is exactly the standard decorator.
import time
def time_fun(flags): def time_arg(func): def my_time(*args, **kwargs): print(f" running at ") print("the flags is {}".format(flags)) return func(*args, **kwargs) return my_time return time_arg @time_fun("itsource") def fun1(arg1, arg2, name): print("+++++{},{},{}++++".format(arg1, arg2, name)) fun1(10, 20, name='rocky') time.sleep(2) fun1(10, 20, name='jim')
1.2.5. Using classes to define decorators
❓ what is the executable?
The object space with call method is called executable object. Every function defined is equivalent to defining call method in space.
❓ how to use classes to implement decorators
@Test # fun = Test(fun)
def fun():
pass
The init method of Test should receive the name of the decorated function
Calling fun() actually calls the call method of Test class
class Test():
def init(self, fn):
self.old_fun = fn
def __call__(self,): ... ... # Decorative content ret = self.old_fun()
@Test
def fun(a, b, name):
pass
fun()
1.3. Multi layer decoration
In actual development, a primitive function can be decorated with multiple decoration functions, which is called multi-layer decoration.
For multi-layer decoration, understand the execution process.
def bold(fn): def wrapper(): return f'<b></b>' return wrapper def italic(fn): def wrapper(): return f'<i></i>' return wrapper @italic @bold def hello(): return 'Hello World' print(hello())
[results]:
<i><b>Hello World</b></i>
1.4. summary
The decorator is actually a function (callable object);
Receiving the name of an old function;
Returns the name of the new function;
Call the old function in the new function;