Analysis of principle and simple usage of Python Decorator

  • 2020-08-22 22:12:25
  • OfStack

This article illustrates the principle and simple usage of Python decorator. To share for your reference, the details are as follows:

Today, finishing decorators, embedded decorators, let decorators with parameters and other forms, very complex, it is a headache. But suddenly the mystery of the decorator was discovered, so simple...

Step 1: Start with the simplest example


# -*- coding:gbk -*-
''' The sample 1:  Use grammar sugar @ To decorate the function "myfunc = deco(myfunc)"
 But the new function is only found at number one 1 Is called multiple times and the original function is called multiple times 1 time '''
def deco(func):
  print("before myfunc() called.")
  func()
  print(" after myfunc() called.")
  return func
@deco
def myfunc():
  print(" myfunc() called.")
myfunc()
myfunc()

This is a simple example of a decorator, but there's a problem here, which is when we call it twice myfunc() Found that the decorator function was called only once. Why is that? To explain this is to give the key to cracking the decorator.

Here's @deco, and myfunc = deco(myfunc) It's the exact same thing, it's just a different way of writing it

1 must remember the above sentence!!

All right, from now on, you just need to do the substitution.

Replace @deco with myfunc = deco(myfunc)

The program first calls deco(myfunc) (Note: in Python the function name is just a function pointer to the first address of the function)

while deco(myfunc) The return value of is the function myfunc() The address of the

So myfunc has not changed, that is, the last two myfunc() A function call is never actually executed deco() .

A classmate asked, clearly printed deco() The contents of the function are not called. This student did not pay attention to the lecture. The first printing was performed in the sentence @deco. Try it yourself and you'll find that "myfunc() called." is printed out three times. The other one is @deco, because @deco is the same as @deco myfunc = deco(myfunc) I've already called it deco() The function.

Step 2: Make sure the decorator is invoked

How do you solve the problem of decorators not being called


# -*- coding:gbk -*-
''' The sample 2:  Use inline wrapper functions to ensure that each new function is called, 
 The parameters and return values of the inline wrapper function are the same as the original function, and the decorator returns the inline wrapper function object '''
def deco(func):
  def _deco():
    print("before myfunc() called.")
    func()
    print(" after myfunc() called.")
    #  You don't have to go back func , should actually return the return value of the original function 
  return _deco
@deco
def myfunc():
  print(" myfunc() called.")
  return 'ok'
myfunc()
myfunc()

I don't really need to explain this, but I'll just do the substitution I did in step 1. Let me just say a few words.

@ deco replaced with myfunc = deco(myfunc)

The program first calls deco(myfunc) Is assigned to myfunc, so myfunc becomes a pointing function _deco() A pointer to the

After the myfunc() It's actually a call _deco()

Step 3: Decorate the function with arguments

The process of solving the case is exactly the same as step 1 and step 2. It will not be repeated again


# -*- coding:gbk -*-
''' The sample 5:  To decorate a function with parameters, 
 The parameters and return values of the inline wrapper function are the same as the original function, and the decorator returns the inline wrapper function object '''
def deco(func):
  def _deco(a, b):
    print("before myfunc() called.")
    ret = func(a, b)
    print(" after myfunc() called. result: %s" % ret)
    return ret
  return _deco
@deco
def myfunc(a, b):
  print(" myfunc(%s,%s) called." % (a, b))
  return a + b
myfunc(1, 2)
myfunc(3, 4)

Step 4: Let the decorator take parameters


# -*- coding:gbk -*-
''' The sample 7:  In the sample 4 Let the decorator take the parameters, 
 And on the 1 The example is much larger than in the outer layer 1 Layer of packaging. 
 The name of the decorative function should actually make more sense '''
def deco(arg):
  def _deco(func):
    def __deco():
      print("before %s called [%s]." % (func.__name__, arg))
      func()
      print(" after %s called [%s]." % (func.__name__, arg))
    return __deco
  return _deco
@deco("mymodule")
def myfunc():
  print(" myfunc() called.")
@deco("module2")
def myfunc2():
  print(" myfunc2() called.")
myfunc()
myfunc2()

What about this parameter decorator? It's actually going to be 1, or it's going to be our substitution

@deco("mymodule") Replace with myfunc = deco("mymodule")(myfunc )

Notice, deco is followed by two parentheses.

Some of you want to know, what does that mean?

It's pretty simple. Let's do it first deco("mymodule") , returns the result _deco

To perform _deco(myfunc) , and the return result is ___

so myfunc = deco(myfunc)0

Solve crimes!

For more information about Python, please see Python Data Structure and Algorithm Tutorial, Python Socket Programming Skills Summary, Python Function Usage Tips summary, Python String Manipulation Tips and Python Introductory and Advanced Classic Tutorial.

I hope this article has been helpful to you in Python programming.


Related articles: