Detailed Explanation of python Custom Decorator Example

  • 2021-07-24 11:17:37
  • OfStack

This article describes the example of python custom decorator. Share it for your reference, as follows:

Let's look at an example first


def deco(func):
  print("before myfunc() called.")
  func()
  print("after myfunc() called.")
  return func
@deco
def myfunc():
  print("myfunc() called.")
# myfunc = deco(myfunc) #  With the above @deco Equivalence 
myfunc()
print("***********")
myfunc()

You will find that the output is

before myfunc() called.
myfunc() called.
after myfunc() called.
myfunc() called.
***********
myfunc() called.

That is to say, the contents of the decorator are only called once. Why?

This is because adding @ deco before the definition of the myfunc () function is essentially equivalent to passing the first address of everything below to func after def myfunc (), followed by adding myfunc = deco (myfunc). Execute this sentence to indicate that func represents the body of the originally defined myfunc (), and the address of the function myfunc () is passed to the deco () function, that is, myfunc- > func, which means that the value of myfunc is exactly the same as that of func. Then execute the contents of the decorator, and finally return to func and pass it to myfunc. Next, when you call myfunc (), you print out "myfunc () called". The second time the myfunc () function is called, only "myfunc () called" is still printed. Why didn't you execute the contents of the decorator the second time? This is because the phrase myfunc = deco (myfunc) is only executed once, and this is the phrase that really executes the contents of the decorator.

The above code shows that the decorator is equivalent to decorating only the function called for the first time, so how to decorate the function called every time? Keep looking


def deco(func):
  def wrapper(*args, **kwargs): # *args, **kwargs Used for receiving func Parameters of 
    print("before myfunc() called.")
    func(*args, **kwargs)
    print("after myfunc() called.")
  return wrapper
@deco
def myfunc(a, b):
  print(a+b)
# myfunc = deco(myfunc) #  With the above @deco Equivalence 
myfunc(1, 2)
print("***********")
myfunc(3, 4)

The output of this code is

before myfunc() called.
3
after myfunc() called.
***********
before myfunc() called.
7
after myfunc() called.

We said that adding @ deco before the definition of myfunc () function is essentially equivalent to the occurrence of def? After myfunc (), pass the first address of everything below to func, followed by the sentence myfunc = deco (myfunc). When the myfunc (1, 2) command is executed, the address of the myfunc function body has already been passed to the deco () function, and wrapper is returned. This is the address represented by myfunc, which is no longer the address of the original myfunc, but the address of the wrapper function. Therefore, whenever myfunc () appears in the future, the wrapper () function is called. That is, myfunc (1, 2) is wrapper (1, 2), so every time myfunc () is called, the contents of the decorator will be executed. The func in the wrapper () function body represents the original myfunc () function body.

How to go one step further to understand the phrase "After def? After myfunc (), first pass the first address of all the following contents to func"? Look:


def deco(func):
  def wrapper(*args, **kwargs): # *args, **kwargs Used for receiving func Parameters of 
    print("wrapper Address of: ", wrapper)
    func(*args, **kwargs)
    print("func Address of: ", func)
  return wrapper
@deco
def myfunc(a, b):
  print("myfunc Address of: ",myfunc)
  print(a+b)
# myfunc = deco(myfunc) #  With the above @deco Equivalence 
myfunc(1, 2)
print("***********")
print(" After modification myfunc Address of: ",myfunc)

Run results:

Address of wrapper: < function deco. < locals > .wrapper at 0x0000023AA9FF58C8 >
Address of myfunc: < function deco. < locals > .wrapper at 0x0000023AA9FF58C8 >
3
Address of func: < function myfunc at 0x0000023AA9FF5840 >
***********
Address of myfunc after modification: < function deco. < locals > .wrapper at 0x0000023AA9FF58C8 >

When the program executes myfunc (1, 2), it is essentially executing wrapper (1, 2), so the address of wrapper is output first, and then the func () function is executed. When the func () function is executed, output the address of myfunc () (see, the value of myfunc is equal to that of wrapper), and print 3. When outputting the address of func () function, it can be seen that the address of func () function is different from that of myfunc () function! ! ! ! That is to say, the body of the original myfunc () function already belongs to func, not myfunc! !

Take one step to witness the miracle! !


def deco(func):
  def wrapper(*args, **kwargs): # *args, **kwargs Used for receiving func Parameters of 
    pass
  return wrapper
@deco
def myfunc(a, b):
  print(a+b)
myfunc(1, 2)

This code has no output. That's because when you execute myfunc (1, 2), you essentially execute wrapper (1, 2). wrapper (1, 2) does nothing, so there is no output. As for the phrase print (a+b), his address already belongs to func.

Decorator with parameters, see other articles

For more information about Python, please see the topics on this site: "Python Data Structure and Algorithm Tutorial", "Python Socket Programming Skills Summary", "Python Function Use Skills Summary", "Python String Operation Skills Summary" and "Python Introduction and Advanced Classic Tutorial"

I hope this paper is helpful to everyone's Python programming.


Related articles: