Explain Python decorator with examples

  • 2021-08-31 08:44:14
  • OfStack

In Python, a function can be passed into a function as a parameter, and a function can also be copied to a variable, and a function can be called through a variable. The decorator can extend the function of a function, make a decorator annotation for the function, and execute the functions defined in the decorator in advance in all functions, thus improving the reuse degree of the code.

Now there is such a scene.

Clock in

There are all kinds of employees in Internet companies, programmers, front desk... programmers need to punch in before turning on the computer, and the front desk needs to open the door early (I don't know who opens the door, assuming here that the front desk opens the door), and the front desk also needs to punch in before opening the door. That is to say, punching in is the first public action of all employees, so the function of punching in can be taken out as public logic.

Common function call method

Naturally, it can be realized as follows.


def di(f):
  print('%s  Clock in , Drop ...' % f.__name__)
  return f()


def boot():
  print(' Turn on ')


def open():
  print(' Open the door ')


if __name__ == '__main__':
  """
   Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk. 
  """
  di(boot)
  di(open)

A function di (f) is defined, which can print the function name information of f.__name__, that is, f, and return the execution result of f ().

Note: If __name__ is imported as a module, module.__name__ is the name of the module itself, and if the module itself is executed as a script, it returns __main__.

Implementation results:

boot punch in, drop...
Turn on
open punch in, drop...
Open the door

In this design, if there are many functions to call, it is very troublesome, so the decorator will come in handy.

Simple Decorator with @ Grammar Sugar

Decorator: A way to add functionality dynamically while code is running, called a "decorator" (Decorator).

Simple decorator

Define an di (f) method, or pass in the logical function to be executed as a parameter, which defines an wrapper function, and the return value is the execution result of f.
In if __name__ = = '__main__':, this decorator is called, and the defined function is not modified, and the function "punch in" is dynamically added during operation.


import functools

#  Simple decorator 
def di(f):
  """
   Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk. 
  :param f:  Incoming 1 Functions 
  :return:
  """
  #  Put the original function's __name__ And other properties are copied to the wrapper()
  @functools.wraps(f)
  def wrapper():
    print('%s  Clock in , Drop ...' % f.__name__)
    return f()
  return wrapper


def boot():
  print(' Turn on ')


def open():
  print(' Open the door ')


if __name__ == '__main__':

  #  No. 1 1 Kinds, simple decorator 
  a = di(boot)
  a1 = di(open)
  print(a.__name__) #  Results wrapper  Plus @functools.wraps(f) The result is  boot
  a()
  a1()

The return value a of di (boot) is the wrapper function, and the wrapper function is called through a () to get the return value of boot. Similarly, di (open) 1.

Results

boot
boot punch in, drop...
Turn on
open punch in, drop...
Open the door

Since the return value a of di (boot) is the wrapper function, the result of print (a.__name__) is of course wrapper. We hope it is boot. What should I do? The annotation of functools. wraps (f) can copy the attributes such as __name__ of the original function boot to wrapper (), and this line of code annotation can also run, so the result of print (a.__name__) is wrapper.

The second kind, @ grammar sugar
With @ grammar sugar, you can also apply decorators to functions. Recommended.


import functools

def di(f):
  """
   Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk. 
  :param f:  Incoming 1 Functions 
  :return:
  """
  #  Put the original function's __name__ And other properties are copied to the wrapper()
  @functools.wraps(f)
  def wrapper():
    print('%s  Clock in , Drop ...' % f.__name__)
    return f()
  return wrapper


# @  Grammatical sugar 
@di
def boot2():
  print(' Turn on ')


@di
def open2():
  print(' Open the door ')
  
  
if __name__ == '__main__':

  #  No. 1 2 Species, @  Grammatical sugar 
  boot2()
  open2()

The @ di tag is equivalent to a2 = di (boot2) a2 (). Don't bother, because the @ symbol is added, you can call the decorator directly with boot2 ().

Results

boot2 punch in, drop...
Turn on
open2 punch in, drop...
Open the door

Business logic function requires parameters

Business logic functions may require parameters, such as:


def boot(name):
  print('%s  Turn on ' % name)

Then, just modify the front decorator to:


import functools

#  Business logic function requires parameters 
def di(f):
  """
   Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk. 
  :param f:  Incoming 1 Functions 
  :return:
  """
  #  Put the original function's __name__ And other properties are copied to the wrapper()
  @functools.wraps(f)
  def wrapper(*args, **kwargs):
    print('%s  Clock in , Drop ...' % f.__name__)
    return f(*args, **kwargs)
  return wrapper


@di
def boot(name):
  print('%s  Turn on ' % name)


if __name__ == '__main__':
  boot('keguang')

Results:

boot punch in, drop...
keguang boot

Add * args and **kwargs parameters to wrapper, and call f (* args, **kwargs) directly in boot. By the way, 1:

* args: 1 Array parameter can be passed in **kwargs: 1 k-v pair parameter can be passed in

The sequence corresponds, and the array parameters come first. Examples:


def f(*args, **kwargs):
  print('args=', args)
  print('kwargs=', kwargs)

print(f(1, 2, 3, a = 'a', b = 'b'))

#  Results 
# args= (1, 2, 3)
# kwargs= {'a': 'a', 'b': 'b'}

Decorator with parameters

If the decorator also takes parameters, for example, now if an employee comes to work early in the morning, < At 9:00, we can give a compliment, which is equivalent to putting a layer of function outside the front di (), di_args, inside wrapper. Use this parameter


import functools

#  Decorator with parameters 
def di_args(time):
  def di(f):
    """
     Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk. 
    :param f:  Incoming 1 Functions 
    :return:
    """
    #  Put the original function's __name__ And other properties are copied to the wrapper()
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
      if time < '9:00':
        print(' It's so early. It's great. . . ')

      print('%s  Clock in , Drop ...' % f.__name__)
      return f(*args, **kwargs)
    return wrapper
  return di


@di_args('8:00')
def boot(name):
  print('%s  Turn on ' % name)


if __name__ == '__main__':
  boot('keguang')

Parameters can be passed in at @ di_args ('8:00'), which is a bit like the annotation in java. Finally, it can be called through boot ('keguang'), and the result is:

It's so early. It's great. . .
boot punch in, drop...
keguang boot

Class decorator

The class decorator relies primarily on the __call__ method of the class, which is called when the decorator is attached to a function using the @ form.


#  Class decorator 
class di(object):
  def __init__(self, f):
    self._f = f

  def __call__(self, *args, **kwargs):
    print('decorator start...')
    self._f()
    print('decorator end...')


@di
def boot():
  print(' Turn on ')


if __name__ == '__main__':
  boot()

With the @ di decorator identity, the di class is instantiated with boot, then the __call__ function is executed, and object indicates that the class can pass in any type parameter.
Running result

decorator start...
Turn on
decorator end...

A typical application scenario of decorator is to log log. If all logic needs to log the running status of the program, you can add log module decorator to these logic (functions) to achieve the corresponding purpose.

The above is an example to explain the details of Python decorator. For more information about python decorator, please pay attention to other related articles on this site!


Related articles: