I finally understand Python decorators

This series of documents:

1. I finally understand the decorator of Python (1)

2. I finally understand the decorator of Python (2)

3. I finally understand the decorator of Python (3)

4. I finally understand the decorator of Python (4)

1, Decorator Foundation (what is a decorator)

Python functions are objects

To understand decorators, you must first understand that functions are objects in Python. This has important connections.

Let's take a simple example:

def shout(word="yes"):
    return word.capitalize()+"!"

print(shout())
# Output:'Yes! '

# As an object, you can assign functions to variables just like any other object
scream = shout

#Note that we do not use parentheses: we do not call a function
#We will“ shout"Put variable“ scream". 
#This means that you can“ scream"Call in“ shout": 

print(scream())
# Output:'Yes! '

#In addition, this means that you can delete the old name'shout',This feature is still available from'scream'access

del shout

try:
    print(shout())
except NameError as e:
    print(e)
    #Output: "name'short'is not defined"

print(scream())
# Output:'Yes! '

Please keep this in mind, and we will talk about it later.

Another interesting feature of Python functions is that they can be defined in another function!

def talk():

    # You can dynamically define a function in "talk"
    def whisper(word="yes"):
        return word.lower()+"..."

    # And And you can use it right away.
    print(whisper())

#Every time you call“ talk",City definition“ whisper",And then in“ talk"Call in“ whisper". 

talk()
# Output: 
# "yes..."

# But "Whistler" does not exist outside the definition of "talk":

try:
    print(whisper())
except NameError as e:
    print(e)
    #Output: "name'whisper'is not defined"

Function reference

OK, I think I'm still reading it? Now let's start the interesting part

You have seen that the function is an object.
Therefore, the function:

  • Can be assigned to variables
  • Can be defined in another function

This means that a function can return another function.

def getTalk(kind="shout"):

    # We have a real-time function
    def shout(word="yes"):
        return word.capitalize()+"!"

    def whisper(word="yes") :
        return word.lower()+"...";

    # Then we go back to it
    if kind == "shout":
        #We do not use "()", so we did not call the function. We are returning this function object
        return shout  
    else:
        return whisper

#Get a function and assign it to a variable: "talk"
talk = getTalk()      

#You can see“ talk"Is a function object:
print(talk)
#Output: <function shot at 0xb7ea817c>

#What the function object returns:
print(talk())
#Output: Yes!

#If you are confused, you can even use it directly:
print(getTalk("whisper")())
#outputs : yes...

More!

If you can return a function, you can pass one of them as a parameter:

def doSomethingBefore(func): 
    print("I do something before then I call the function you gave me")
    print(func())

doSomethingBefore(scream)
#Output: 
#I do something before then I call the function you gave me
#Yes!

Well, you only have all the information you need to know about the decorator.
As you can see, decorators are "wrappers", which means that they enable you to execute code before and after decorating a function without modifying the code content of the function itself.

Decoration by hand

You will know how to do this manually:

#Decorator is a function that takes another function as a parameter
def my_shiny_new_decorator(a_function_to_decorate):

    # Internally, the decorator dynamically defines a function: wrappers.
    # This functionality will be wrapped outside the original functionality so that it can execute code before and after the code.
    def the_wrapper_around_the_original_function():

        # Put the code to be executed here before calling the original function
        print("Before the function runs")

        #Call function here (use parentheses)
        a_function_to_decorate()

        # Place the code to be executed here after the original function is called
        print("After the function runs")

    #So far“ a_function_to_decorate"Never implemented.
    #We return to the wrapper function we just created.
    #A wrapper contains functions and code that executes before and after the code. Ready to use!
    return the_wrapper_around_the_original_function

#Now, suppose you create a function that you don't want to modify.
def a_stand_alone_function():
    print("I am a stand alone function, don't you dare modify me")

a_stand_alone_function() 
#Output: I am a stand alone function, don't you dare modify me

#Therefore, you can decorate it to extend its behavior.
#Just pass it to the decorator, which will be dynamically wrapped in
#In any code you want and return for you the new features you are ready to use:

a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()

#Output:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

Now, you might want to call a_stand_alone_function a_ Stand_ Alone_ Function_ It is called by the modified.
It's simple, just a_stand_alone_function overrides my with the function returned by the following method_ Shiny_ New_ Decorator:

a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#Output:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

#This is the job of the decorator!

Mystification of ornaments

Here is the syntax for using decorators:

@my_shiny_new_decorator
def another_stand_alone_function():
    print("Leave me alone")

another_stand_alone_function()  
#Output:  
#Before the function runs
#Leave me alone
#After the function runs

Yes, that's all@ decorator is just a shortcut to:

another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)

The decorator is just Decorator design mode Python variant of.
Several classic design patterns are embedded in Python to simplify development (such as iterators).

Of course, you can accumulate decorators:

def bread(func):
    def wrapper():
        print("</''''''\>")
        func()
        print("<\______/>")
    return wrapper

def ingredients(func):
    def wrapper():
        print("#tomatoes#")
        func()
        print("~salad~")
    return wrapper

def sandwich(food="--ham--"):
    print(food)

sandwich()
#Output: --ham--
sandwich = bread(ingredients(sandwich))
sandwich()
#Output:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>

Use Python decorator syntax:

@bread
@ingredients
def sandwich(food="--ham--"):
    print(food)

sandwich()
#outputs:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>

It is important that you set the order of decorator items, such as:

@ingredients
@bread
def strange_sandwich(food="--ham--"):
    print(food)

strange_sandwich()
#outputs:
##tomatoes#
#</''''''\>
# --ham--
#<\______/>
# ~salad~

This article was first published on BigYoung station

Tags: Python

Posted by lookee on Mon, 30 May 2022 18:28:38 +0530