Higher-order functions

A higher-order function satisfies any of the following conditions:

  • You can accept functions as arguments
  • You can return a function as a return value
########## accepts the function as argument ##########
f = abs

def add(x, y, f) :
    return f(x) + f(y)

print(add(-1, -2, f))

########## returns the function as the return value ##########
def hello() :
    print('Hello World')

def wrapper(func) :
    return func

f = wrapper(hello)
f()
Copy the code

Closure

Let’s look at the scope of the variable:

  • L: internal scope of the local function
  • If you want additional recommendations on this. E: Between inside and inside functions.
  • G: global Global scope
  • B: Build-in built-in scope (members automatically imported by the parser)

The priority of the variable scope lookup process is LEGB(L>E>G>B).

def func(lst) :
    def in_func() :
        return len(lst)
    return in_func

f = func([1.2.3])
print(f())
Copy the code

A closure is a case in which an inner function refers to a variable of the outer function (parameters are also variables) and then returns the inner function.

A decorator

What if we define a function that wants to add functionality dynamically at run time, but we don’t want to change the function code? We think of higher-order functions, which can take functions as arguments and return functions, so can we take a function, wrap it, and return a new function, so we can solve this problem, as follows:

def f1(x) :
    return x * 2
# fn is a decorator function implemented as a higher-order function
def fn(f) :
    def new_fn(x) :
        print('call ' + f.__name__ + '()')
        return f(x)
    return new_fn
# call
f1 = fn(f1)
print(f1(5))
Copy the code

Python’s built-in @ syntax simplifies the invocation of decorators, as shown below:

@fn
def f1(x) :
    return x * 2
Copy the code

A decorator function with no arguments is defined above. Let’s see how decorators with arguments are defined:

def log(prefix) :
    def log_decorator (f) :
        def wrapper(*args, **kw) :
            print('[' + prefix + '] ' + ' call ' + f.__name__ + '()')
            return f(*args, **kw)
        return wrapper
    return log_decorator

@log('NOTICE')
def f1(x) :
    return x * 2

print(f1(5))
Copy the code

So the parameterized decorator function returns a new function, which then takes f1() as an argument and returns the new function.

A decorator is a combination of higher-order functions, nested functions, and closures.