高阶函数
满足如下任一条件都是高阶函数:
- 可以接受函数作为参数
- 可以将函数作为返回值返回
########## 接受函数作为参数 ##########
f = abs
def add(x, y, f):
return f(x) + f(y)
print(add(-1, -2, f))
########## 将函数作为返回值返回 ##########
def hello():
print('Hello World')
def wrapper(func):
return func
f = wrapper(hello)
f()
闭包(Closure)
先来看一下变量的作用域:
- L:local 函数内部作用域
- E:enclosing 函数内部与内嵌函数之间(函数定义的变量可以被内嵌函数使用)
- G:global 全局作用域
- B:build-in 内置作用域(解析器自动导入的成员)
变量作用域查找过程的优先级是:LEGB(L>E>G>B)。
def func(lst):
def in_func():
return len(lst)
return in_func
f = func([1,2,3])
print(f())
像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包。
装饰器
如果我们定义了一个函数想在运行时动态增加功能,又不想改动函数本身的代码,如何解决这个问题呢?我们想到了高阶函数,高阶函数可以接收函数作为参数,可以返回函数,那么我们是否可以接收一个函数,对其包装,然后返回一个新函数,这样就可以解决这个问题了,如下所示:
def f1(x):
return x * 2
# fn就是一个用高阶函数实现的一个装饰器函数
def fn(f):
def new_fn(x):
print('call ' + f.__name__ + '()')
return f(x)
return new_fn
# 调用
f1 = fn(f1)
print(f1(5))
Python内置的@语法简化了装饰器的调用,如下所示:
@fn
def f1(x):
return x * 2
上面定义的是一个不带参数的装饰器函数,然后看下带参数的装饰器如何定义:
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))
所以带参数的装饰器函数先返回一个新函数,然后让这个函数接收f1()函数作为参数并再返回新函数。
装饰器就是高阶函数、嵌套函数、闭包三者的结合。