0%

闭包(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
# 通过装饰器 add_func_runtime扩展原来函数的功能,使得原来的add函数能够计算执行时间
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) # Func:add cost time:0:00:00

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__}")
# 若注释掉@functools.wraps(func),则展示为Func Doc:wrapper
# 若不注释,则展示为Func Doc:minux
print(f"Func Name:{minux.__name__}")
# 若注释掉@functools.wraps(func),则展示为Func Name:wrapper
# 若不注释,则展示为Func Name:minux

工厂函数

由于闭包的外部函数返回的是内部函数,根据此特性可以实现工厂函数,生成不同类型的函数。一般来说,实现数值的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)) # 9
power_of_3 = power_of_n(3)
print(power_of_3(3)) # 27

实现缓存

由于闭包具有能够保留外层函数的局部变量到内存中的特性,因此可以使用该特性将一些比较重要的数据临时保存到缓存中,避免重复计算,但要加强内存的管理,避免内存泄漏。

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')) # 1
set_item('b', 2)
print(get_item('b')) # 2