Regardless of project or the interview cannot leave the decorator topic, powerful is that it can be a decorator without modifying the original business logic, extending the code under the condition of permission check, user authentication, logging, performance testing, transaction processing, such as the cache is an excellent application scenarios, a decorator it can maximize the reuse of code.

But why are decorators so difficult for beginners, and I think it’s essentially a poor understanding of Python functions, because decorators are essentially functions

The function definitions

To understand how functions work, let’s start with one of the simplest function definitions:

def foo(num):
    return num + 1Copy the code

The above defines a function named foo, which can also be thought of as a variable name that points to a function object

To call a function, simply parenthesize the name of the function and pass the necessary arguments (if the function was defined with any).

value = foo(3)
print(value) # 4Copy the code

The variable name foo now refers to the

function object, but it can also refer to another function.

def bar(a):
    print("bar")
foo = bar
foo() # barCopy the code

Function as the return value

In Python, everything is an object, including functions, which can be returned as integers by other functions, such as:

def foo(a):
    return 1

def bar(a):
    return foo

print(bar()) # <function foo at 0x10a2f4140>

print(bar()()) # 1 
# is equivalent to
print(foo()) # 1Copy the code

The return value from calling the function bar() is a function object, and since the return value is a function, we can continue to call the return value (remember: Calling bar()() is equivalent to calling foo(), because the variable foo points to the same object that bar() returns.

Function as argument

Functions can also be arguments to functions like integers, for example:

def foo(num):
    return num + 1

def bar(fun):
    return fun(3)

value = bar(foo)
print(value)  # 4Copy the code

Bar takes an argument that is a callable function object. When foo is passed to bar, foo and fun refer to the same function object, so calling fun(3) is the same as calling foo(3).

Nested function

Not only can functions be arguments and return values, functions can also be defined in another function and exist as nested functions, for example:

def outer(a):
    x = 1
    def inner(a):
        print(x)
    inner()

outer() # 1Copy the code

Inner is a nested function that can access variables from the outer function. When we call outer, three things happen:

  1. To the variablexAssignment 1
  2. Define nested functionsinnerThe code in inner is not executed because the function has not been called until step 3
  3. Call inner to execute the code logic in inner.

closure

Here’s another example:

def outer(x):
    def inner(a):
        print(x)

    return inner
closure = outer(1)
closure() # 1Copy the code

The closure is essentially a function (inner) that refers to a free variable (x). The closure is a function (inner) that refers to a free variable (x).

A decorator

Read on:

def foo(a):
    print("foo")Copy the code

This is probably the simplest business code ever written. It doesn’t work, but it makes sense. Now, there is a new requirement to execute this function with logging:

def foo(a):
    print("Logging started")
    print("foo")
    print("Logging finished")Copy the code

The only problem with this implementation is that it has to hack into the original code and add logging logic, as it would if there were dozens of other such functions to add logging, which is obviously not Pythonic at all. Is it possible to implement logging without modifying the business code in advance? The answer is decorators.

def outer(func):
    def inner(a):
        print("Logging started")
        func() # business function
        print("Logging finished")
    return inner

def foo(a):
    print("foo")

foo = outer(foo) 
foo()Copy the code

I didn’t change any of the logic in foo. I just reassigned foo to a new function object. Finally, foo() is called, and not only is the log printed, but the business logic is done. Now let’s analyze its execution flow.

The outer function here is essentially a decorator. The decorator is a closure that takes a function as an argument and returns a new function. The decorator is essentially a function. Outer returns the inner function, which has business code in addition to logging operations. After reassigning to foo, calling foo() is equivalent to calling inner().

Foo before reassigning:

Foo = outer(foo) after reassignment

In addition, Python provides a syntactic sugar @ for decorators, which is used in function definitions:

@outer
def foo(a):
    print("foo")

foo()Copy the code

This eliminates the need to manually reassign to Foo.

Do you understand decorators by now? Of course, decorators can be more complex, such as decorators that accept parameters, class-based decorators, and so on. The next article can write about the application scenarios of decorators.

Simultaneously published: foofish.net/understand-…

Public id: Zen of Python