1) What is a python decorator?
Python decorator is a very powerful function, an excellent design pattern, which abstracts the repeated content and gives a function other functions without changing the function itself.
- Simply put, modifiers are functions that modify the functions of other functions.
- It makes the code extremely concise and easy to maintain.
Why do I need modifiers?
The function of decorator is to add additional functions to existing functions or objects.
- The decorator is essentially a Python function, which allows other functions to add additional functions without any code changes. The return value of the decorator is also a function object.
- It is often used in scenarios with various requirements, such as log insertion, performance testing, transaction processing, caching, permission verification and so on. The decorator is an excellent design to solve this kind of problem.
With decorators, we can extract a large number of similar code that has nothing to do with the function itself and continue to reuse it.
2) How to write modifiers?
Background:
-
A program realizes say_hello() and say_goodbye() has two functions:
def say_hello(): print "hello!" def say_goodbye(): print "goodbye!" if __name__ == '__main__': say_hello() say_goodbye()
-
The boss requires that the name of the incoming function be recorded before calling each method, such as:
[DEBUG]: Enter say_hello() Hello! [DEBUG]: Enter say_goodbye() Goodbye!
2.1 primary modifier
Version 1.0
Earlier (Python version < 2.4, before 2004), the way to add additional functions to a function was as follows:
def debug(func): def wrapper(): print "[DEBUG]: enter {}()".format(func.__name__) return func() return wrapper def say_hello(): print "hello!" say_hello = debug(say_hello) # Add functions and keep the original function name unchanged
- The debug function is actually a decorator. It wraps the original function and returns another function, adding some additional functions.
*Python format formatting function
Python2. Starting from 6, a new function str.format() for formatting strings is added, which enhances the function of string formatting.
- The basic grammar is to replace the previous% by {} and:.
- The format function can accept unlimited parameters, and the positions can be out of order.
>>> "{}-{}".format("Hello","goodbye") # Do not set the specified location, in the default order 'Hello-goodbye' >>> "{1}-{0}".format("Hello","goodbye") # Set the specified location 'goodbye-Hello' >>> "{1}-{0}-{1}".format("Hello","goodbye") # Set the specified location 'goodbye-Hello-goodbye' >>> "Website name:{name}, address {url}".format(name="Rookie tutorial", url="www.runoob.com") # You can set parameters, or set parameters through dictionary or list index 'Website name: rookie tutorial, address www.runoob.com'
*Properties of Python functions
A function in python is an object that has properties that belong to the object. In addition, functions can customize their own properties.
- View the properties of the function object: dir(func_name)
- There is an attribute__ name__, It represents the name of the function.
Version 2.0
The @ syntax sugar is supported in later versions of Python to make the code more elegant. The following code is equivalent to the earlier writing method:
def debug(func): def wrapper(): print "[DEBUG]: enter {}()".format(func.__name__) return func() return wrapper @debug def say_hello(): print "hello!"
*Syntax sugar
Also translated as sugar coated grammar, it refers to a special grammar in computer language.
- This syntax has no effect on the function of the language, but it is more convenient for programmers to use.
- Generally speaking, using syntax sugar can increase the readability of the program and reduce the chance of program code error.
Common syntax sugar:
- Form of list generating formula: [operation on x for x in set]
- A decorator is essentially a function that takes a function as an argument to another function.
This is the simplest decorator.
- But there is a problem. If the decorated function needs to pass in parameters, the decorator is broken because the returned function cannot accept parameters.
Version 3.0
def debug(func): def wrapper(*args, **kwargs): # Specify cosmic invincible parameters print "[DEBUG]: enter {}()".format(func.__name__) print 'Prepare and say...', return func(*args, **kwargs) return wrapper # return @debug def say(something): print "hello {}!".format(something)
- You can specify the decorator function wrapper to accept the same parameters as the original function. The decorator can be used for any target function through the variable parameter * args and keyword parameter * * kwargs provided by Python.
Variable parameter * args
Principle: the python interpreter will assemble a set of parameters passed in into a tuple and pass it to the variable parameters.
Keyword parameter * * kwargs
Principle: the python interpreter will assemble a set of passed in parameters into a dict and pass it to the keyword parameters.
2.2 advanced modifier
Decorators with parameters and class decorators belong to advanced content. It's best to understand these conventions and decorators before you have them.
- Closure: when a function is returned as an object, it takes external variables to form a closure.
- Closures can be understood as lightweight interface encapsulation.
- For details, please refer to: Talk about closures in Python
-
Decorator with parameters
Assuming that the decorator we mentioned above needs to complete the function of not only typing log information after entering a function, but also specifying the level of log, then the decorator will be like this:
def logging(level): def wrapper(func): def inner_wrapper(*args, **kwargs): print("[{level}]: enter function {func}()".format( level=level, func=func.__name__)) return func(*args, **kwargs) return inner_wrapper return wrapper @logging(level='INFO') def say(something): print("say {}!".format(something)) # If the @ syntax is not used, it is equivalent to # say = logging(level='INFO')(say) @logging(level='DEBUG') def do(something): print("do {}...".format(something)) if __name__ == '__main__': say('hello') do("my work")
-
Decorator based on class implementation
class logging(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print("[DEBUG]: enter function {func}()".format( func=self.func.__name__)) return self.func(*args, **kwargs) @logging def say(something): print("say {}!".format(something)) if __name__ == '__main__': say('hello')
-
Class decorator with parameters
What is accepted in the constructor is not a function, but the parameters passed in. Save these parameters through the class. Then reload__ call__ The method is to accept a function and return a function.
class logging(object): def __init__(self, level='info'): self.level = level def __call__(self, func): def wrapper(): print("[{level}]: enter function {func}()".format( level=self.level, func=func.__name__)) return func return wrapper() @logging(level='alarm') def say(something): print("say {}!".format(something)) if __name__ == '__main__': say('hello')
3) Common pit of decorator
-
Wrong location code
If you have no bottom in mind, it's best not to add logic functions outside the decorator function, otherwise the decorator will be out of control.
-
Wrong function signature and document
-
Cannot decorate @ staticmethod or @ classmethod
[some contents refer to]
- Explain Python's decorators in detail: https://www.cnblogs.com/cicaday/p/python-decorator.html#_caption_0
- Python function class syntax: https://segmentfault.com/a/1190000006261012