Introduction to function decorators

First understand the concepts of scope, higher-order functions, and closures

scope

Global variables (defined within modules), local variables (defined within functions), nested scopes (scope of internal functions), built-in scopes (python built-in definitions)

a=1  Global variables, defined in modules

def foo() :
    b=2 Local variables, defined in functions
    print("a1:",a)
    print("b1:",b)
    def inner() :
        c=3 # nested scope
        print("b3:", b)
        print("c3:", c)
    print("b4:", b)
    # print("c4:", c
print("a2:",a)
# print("b2:", b

foo()
print(__name__) # Built-in scope, defined in Python
Copy the code
    a2: 1
    a1: 1
    b1: 2
    b4: 2
    __main__
Copy the code

Higher-order functions

Function names can be assigned to other objects, returned as values, and passed as arguments

1. Function names can be assigned to other objects ================
def foo() :
    print("Execute foo")

Method a #
a=foo() 

Method # 2
a=foo Function names can be assigned to other objects
a()

# the resultsExecute function foo2. The function name can be used as the return value ================
def foo() :
    print("Execute foo")
    def inner() :
        print("Execute inner function")
    return inner  The function name is a variable and can be used as a return value
    
print("- perform a = foo () -- -- -- -- -- -")
a=foo() # return the variable inner and execute foo
print("- perform a () -- -- -- -- -- -")
a()  # equivalent to inner(), executes inner

# the results- perform a = foo () -- -- -- -- -- - ִ perform function foo -- () -- -- -- -- -- - a ִ perform inner function3. The function name can be passed as an argument ================
def foo(func) :
    func()

def bar() :
    print("Execute bar function")

foo(bar)

# the resultsExecute bar functionCopy the code

closure

Call external scoped variables (but not global variables) in an inner function

x="Global variables, defined in modules"
def outer() :
    y="Local variables, defined in the function."
    def inner() :
        print(y)
    return inner

Call inner
outer()() Method a #

a=outer() Method # 2
a()

These methods are closures that call external scoped variables (but not global variables) in an inner function.

# the resultsLocal variables are defined in the functionCopy the code

A decorator

Allow extension of existing function code, prohibit modification of existing function code; For example: decorated function A(), decorated function B(A), on the decorated function A() @ decorated function B, equivalent to A=B(A), call only A(), has achieved the above purpose to extend the existing function without modifying the existing function code

Method 1: Write a decorator function to extend the function, the original method as the decorator function argument

import time

def foo() :
    print("Call a lot of interfaces")
    time.sleep(3)

def show_time(func) :
    beginTime=time.time()
    func()
    endTime = time.time()
    print("Total time :",endTime - beginTime)

show_time(foo)
""" """ """ """ """

# the resultsTotal time spent calling many interfaces:3.002992630004883
Copy the code

Method 2: Decorators return functions and simplify calls with decorators

import time

def show_time(func) : # decorator function
    def inner() :
        beginTime=time.time()
        func()
        endTime = time.time()
        print("Total time :",endTime - beginTime)
    return inner

@show_time # equivalent to foo=show_time(foo) #foo=inner
def foo() : # Decorates the function
    print("Call a lot of interfaces")
    time.sleep(1)

#---- Call method 1: no decorator ----------
foo=show_time(foo) #foo=inner
foo()

#---- call method two: the decorator function on @decorator function ----------
foo()

""" The above is a simple decorator. ""
# the resultsTotal time spent calling many interfaces:1.0051441192626953
Copy the code

Function decorator with arguments

import time

def show_time(func) :
    def inner(case_name) :
        beginTime=time.time()
        func(case_name)
        endTime = time.time()
        print("Total time :",endTime - beginTime)
    return inner

@show_time
def foo(case_name) : #foo takes arguments, inner and func take arguments
    print("Call a lot of interfaces")
    time.sleep(1)

foo('parameters')
""" Foo takes arguments, inner and func calls foo take arguments. """
# the resultsTotal time spent calling many interfaces:1.0126347541809082
Copy the code

Function decorator with arguments – variable length arguments

import time

def show_time(func) :
    def inner(*args,**kwargs) : # variable length parameter
        beginTime=time.time()
        func(*args,**kwargs)
        endTime = time.time()
        print("Total time :",endTime - beginTime)
    return inner

@show_time
def foo1(a,b) :
    print("Foo1 calls a lot of interfaces")
    time.sleep(1)

@show_time
def foo2(a,b,c,d) : 
    print("Foo2 calls a lot of interfaces")
    time.sleep(1)

foo1(Parameters' a '.'parameter b')
foo2(Parameters' a '.'parameter b'.'parameter c'.'d parameters')

# the resultsTotal time spent calling many interfaces for foo1:1.001772403717041Total time spent calling many interfaces for foo2:1.0102813243865967
Copy the code

Multiple decorators execute in sequence

def dec1(func) :
    print("1111")
    def one() :
        print("2222")
        func()
        print("3333")
    return one


def dec2(func) :
    print("aaaa")
    def two() :
        print("bbbb")
        func()
        print("cccc")
    return two

@dec1
@dec2
def foo() :
    print("Call a lot of interfaces")

foo()
"" multiple decorators are executed in order from the last decorator to the first decorator, and then the function itself. ""

# the results
aaaa
1111
2222BBBB calls many interface CCCCS3333
Copy the code

Beginner class decorator

Class decorators are essentially the same as function decorators, adding extra functionality to other functions. Using class decorators can be done directly by relying on the __call__ method inside the class, which is called when the class decorator is attached to a function using the @ form. You do not need to define nested functions in decorator functions to implement decorator functions, as function decorators do.

__call__ method

class A:
        pass
a=A()
a()

# the results
TypeError: 'A' object is not callableCan't callCopy the code
class A:
        def __init__(self) :
                self.name="AAA"
        def __call__(self) :The __call__ method is implemented in the # class
                print("Class implements the __call__ method :"+self.name)

a=A()
a()
Class objects can be called, and the __call__ method is automatically executed when the class object is called.

# the resultsClass implements the __call__ method :AAACopy the code

Class decorator instance

import time

class show_time() :
        def __init__(self, func) :  Initializes the arguments passed into the function object
                self._func = func

        def __call__(self) :  # Define __call__ method to implement decorator function directly
                beginTime = time.time()
                self._func()
                endTime = time.time()
                print('Total time :', (endTime - beginTime))

@show_time  # Foo=show_time(Foo)
def Foo() :
        print('Call a lot of interfaces')
        time.sleep(1)

Foo()# Foo=show_time(Foo)()

# the resultsTotal time spent calling many interfaces:1.0099809169769287
Copy the code