Overview
An adorner is essentially a Python function that allows other functions to add extra functionality without any code changes, and the return value of the adorner is also a function object.
We need a decorator that can test the run time of the function, which can be defined as follows:
def timer(func): def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print("Run time is: %s" % (end_time - start_time)) return res return wrapper
Because it is a decorator, it takes a function as an argument and returns a function. We will use the Python @ syntax to place the decorator at the definition of the function:
@timerdef fun(): time.sleep(1) print("This is a test") return "OK"
The result of the operation is:
This is a testRun time is: 1.0000572204589844OK
Putting @timer in Fun () is equivalent to executing a statement:
fun = timer(fun)
If the decorator itself needs to pass in parameters, it is necessary to write a higher-order function that returns decorator, such as a name:
def timer(name): def decorator(func): def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print("Name is: %s ; Run time is: %s" % (name, (end_time - start_time))) return res return wrapper return decorator
The call and the results are displayed as follows:
@timer("Lance#")def fun(): time.sleep(1) print("This is a test") return "OK"
This is a testName is: Lance# ; Run time is: 1.0000572204589844OK
Compared to the two-layer nested decorator, the three-layer nesting effect is this:
fun = timer("Lance#")(fun)
Because a function is also an object, it also has properties such as __name__.
In the fun () function before the adorner, calling the fun __name__ property results in ' fun ', but after the decorator decoration function, their __name__ has changed from the original ' fun ' to ' wrapper '
Therefore, it is necessary to copy the original function's __name__ and other properties into the wrapper () function, otherwise, some code that relies on the function signature will be executed in error.
Python's built-in Functools.wraps can accomplish this task, so a complete decorator is written as follows:
import functoolsdef timer(func): @functools.wraps(func) def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print("Run time is: %s" % (end_time - start_time)) return res return wrapper
The overall code is as follows:
__Author__ = "Lance#"# -*- coding = utf-8 -*-import timeimport functoolsdef timer(name): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print("Name is: %s ; Run time is: %s" % (name, (end_time - start_time))) return res return wrapper return decorator@timer("Lance#")def fun(): time.sleep(1) print("This is a test") return "OK"if __name__ == '__main__': print(fun())
Python Decorator Example Analysis