闭包(Closure)是一种在函数内部定义的函数,并且该内部函数可以访问外部函数的局部变量。这样的内部函数被称为闭包,因为它“封闭”了外部函数的环境,包含了外部函数的变量。
闭包有很多优点,例如:
1、可以避免使用全局变量,提高程序的可维护性;
2、可以实现类似于私有变量的功能,提高程序的安全性;
3、可以实现延迟执行和缓存结果,提高程序的性能。
但是,闭包也有一些缺点,例如:
1、可能会占用较多的内存空间,因为闭包会保留外部函数的状态;
2、可能会导致循环引用的问题,如果闭包中引用了外部函数的变量,而这些变量又引用了闭包中的变量,就会出现循环引用的问题。
装饰器
装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数,通常在其中包含对原始函数的修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import datetime
def add_func_runtime(func): def wrapper(*args, **kwargs): start_time = datetime.datetime.now() func(*args, *kwargs) end_time = datetime.datetime.now() runtime = end_time-start_time print(f"Func:{func.__name__} cost time:"+str(runtime)) return func return wrapper
@add_func_runtime def add(x, y): return x+y
if __name__ == '__main__': add(1, 2)
|
functools.wraps 是functools模块中自带的一个装饰器,可用于装饰器的内层函数, 抵消装饰器的副作用, 因为使用装饰器后, 原函数被内层函数赋值覆盖, 函数名称等信息丢失了(装饰器仅仅是不改变函数原有功能),示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import datetime import functools
def use_functools(func): @functools.wraps(func) def wrapper(*args, **kwargs): ''' wrapper ''' func(*args, **kwargs) return func return wrapper
@use_functools def minux(x, y): ''' minux ''' return x-y
if __name__ == '__main__': print(f"Func Doc:{minux.__doc__}") print(f"Func Name:{minux.__name__}")
|
工厂函数
由于闭包的外部函数返回的是内部函数,根据此特性可以实现工厂函数,生成不同类型的函数。一般来说,实现数值的2次方,可以定义一个函数,返回参数的2次方即可。当我们需要实现不同场景的幂函数,可以s使用闭包返回一个工厂函数,这样就不用定义n个幂函数了,如下。
1 2 3 4 5 6 7 8 9 10 11
| def power_of_n(n): def inner(x): return x ** n return inner
if __name__ == '__main__': power_of_2 = power_of_n(2) print(power_of_2(3)) power_of_3 = power_of_n(3) print(power_of_3(3))
|
实现缓存
由于闭包具有能够保留外层函数的局部变量到内存中的特性,因此可以使用该特性将一些比较重要的数据临时保存到缓存中,避免重复计算,但要加强内存的管理,避免内存泄漏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def cache(): data = {}
def get(key): return data[key]
def set(key, value): data[key] = value return get, set
if __name__ == '__main__': get_item, set_item = cache() set_item('a', 1) print(get_item('a')) set_item('b', 2) print(get_item('b'))
|