python notes -- understanding of grammar sugar @

Posted by kaupp on Mon, 07 Feb 2022 21:39:11 +0100

Let's start with a simple decorator:

def decoration(fun):
    def inner(x, y):
        a = fun(x, y)
        print(a)
        return a
    return inner


@decoration
def fun(x, y):
    return x + y


fun(4, 5)

The function of this is to add a printing function on the basis of the original. Then the problem comes. How does python execute this code step by step?

Let's take a look at my guess first: @ decoration is actually equivalent to: fun = decoration(fun)

When python runs from top to bottom to @ decoration, it will execute the fun = decoration(fun) statement instead of running to def fun(x, y) immediately. If you don't believe it, you can run this Code:

def decoration(fun):
    def inner(x, y):
        a = fun(x, y)
        print(a)
        return a
    return inner


@decoration
def fun(x, y):
    return x + y

Operation results:

We can see that there is no running result, but what if we add a print statement inside the decoration?

def decoration(fun):
    print('I run successfully')

    def inner(x, y):
        a = fun(x, y)
        print(a)
        return a
    return inner


@decoration
def fun(x, y):
    return x + y

Operation results:

You see, I didn't call the function decoration and fun. They will run decoration because the effect of syntax sugar @ decoration is equivalent to the statement fun = decoration(fun). When running to syntax sugar @ decoration, it is equivalent to executing the statement fun = decoration(fun),

At this time, fun is equivalent to the return value of decoration, that is, the function name inner, so the next time we call the fun function, we actually call the function inner(), so as to achieve the purpose of decoration

 

Let's look at another strange example:

def decoration(fun):
    a = fun()
    print(a)
    return a


@decoration
def fun():
    return 10

This is equivalent to:

def decoration(fun):
    a = fun()
    print(a)
    return a


def fun():
    return 10


fun = decoration(fun)

Their values are printed out as 10

The syntax sugar is still effective, but some people have noticed that the function of fun is still 10 in the end. I can tell you for sure that the current fun == 10 is equal to the return value of decoration(fun)

def decoration(fun):
    a = fun()
    print(a)
    return a


@decoration
def fun():
    return 10


print('Now? fun The value of is:', fun)

result:

Can I still use fun () later? The answer is no, because fun has become a variable pointing to object 10 instead of a function. If you call fun() later, it will report an error that the integer type is not redeemable:

def decoration(fun):
    a = fun()
    print(a)
    return a


@decoration
def fun():
    return 10


fun()

Error reporting result:

PS F:\7.vscode> & "C:/Program Files (x86)/Microsoft Visual Studio/Shared/Python37_64/python.exe" f:/7.vscode/Test 2.py
10
Traceback (most recent call last):
  File "f:/7.vscode/Test 2.py", line 12, in <module>
    fun()
TypeError: 'int' object is not callable

See, isn't it amazing? Secretly tell you, classes can also act as decorators:

class Decoration:
    def __init__(self, fun):
        self.wife = 'Gu He Weihua'

    def __call__(self, wife_two):
        print('First wife:', self.wife)
        print('mistress:', wife_two)


@Decoration
def fun(wife):
    pass


fun('Shida Heiyu')

The result is:

PS F:\7.vscode> & "C:/Program Files (x86)/Microsoft Visual Studio/Shared/Python37_64/python.exe" f:/7.vscode/Test 1.py

First wife: Gu He Weihua
 mistress: Shida Heiyu

Let me explain to you: first, is the syntax sugar @ Decoration equivalent to fun = Decoration(fun), equivalent to instantiating an object fun, which is an instantiated object. We can use fun WiFi prints out my wife 'Guhe Weihua':

class Decoration:
    def __init__(self, fun):
        self.wife = 'Gu He Weihua'

    def __call__(self, wife_two):
        print('First wife:', self.wife)
        print('mistress:', wife_two)


@Decoration
def fun(wife):
    pass


print(fun.wife)
# fun('shida Heiyu ')

Of course, the result is typed:

PS F:\7.vscode> & "C:/Program Files (x86)/Microsoft Visual Studio/Shared/Python37_64/python.exe" f:/7.vscode/Test 1.py

Gu He Weihua

So why can an object fun after instantiation be written in the form of fun()? That's because__ call__ This demon, ghost, ox, ghost, snake and God are making trouble. You can check python for details__ call__ Usage, see if the handle has the illusion of decoration-_-

Topics: Python