python编程之闭包

什么是闭包

在Python中,闭包(Closure)是指一个函数(称为内部函数)捕获了其外部作用域中的变量,并且可以在其内部函数范围之外被调用。换句话说,闭包可以访问其定义时所处环境中的变量,即使在其定义之后这些变量的作用域已经消失了。

闭包的代码结构

1
2
3
4
5
6
7
8
9
10
11
def send_message(message):
def print_message():
print(message) # 获取的是外部函数的形式参数

# 在外部函数中返回内部函数的地址
return print_message


# 创建一个变量去接收内部函数地址
func_obj = send_message('python天下第一...')
func_obj()

上面这段代码是闭包的基本结构,在send_message函数的内部定义了一个print_message函数,send_message函数返回的是内部函数print_message的地址,并且print_message函数可以访问到外部函数send_message的形式参数。func_obj = send_message(‘python天下第一…’),这一段代码是将send_message函数中的内部函数print_message的函数地址值赋值给了func_obj,所以func_obj()实际上就是执行了内部函数print_message。

利用闭包的特性完成代码的复用性

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def create_calculator(operation):
def add(x, y):
return x + y

def subtract(x, y):
return x - y

def multiply(x, y):
return x * y

def divide(x, y):
if y != 0:
return x / y
else:
return "Error: Division by zero!"

if operation == "add":
return add
elif operation == "subtract":
return subtract
elif operation == "multiply":
return multiply
elif operation == "divide":
return divide
else:
return None

# 创建加法器
add_calculator = create_calculator("add")
result = add_calculator(5, 3)
print(result) # 输出 8

# 创建减法器
subtract_calculator = create_calculator("subtract")
result = subtract_calculator(10, 4)
print(result) # 输出 6

# 创建乘法器
multiply_calculator = create_calculator("multiply")
result = multiply_calculator(7, 2)
print(result) # 输出 14

# 创建除法器
divide_calculator = create_calculator("divide")
result = divide_calculator(8, 2)
print(result) # 输出 4.0

在上面的代码中,create_calculator函数返回了不同的内部函数(add、subtract、multiply、divide),这些内部函数捕获了外部函数中的变量operation。通过调用create_calculator并传递不同的操作类型,我们可以创建不同功能的计算器,实现了代码的复用。

修改闭包中的形式参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def counter(start=0):
def add():
nonlocal start # 针对函数参数
start += 1
return start

return add


obj = counter(10)
print(obj())

"""
global: 作用于不可变对象且这个对象是一个全局的
nonlocal: 作用于不可变对象且这个对象具有作用域的
"""

在上面这段代码中,我们定义了一个函数counter,在函数counter的内部定义了一个函数add,内部函数可以访问到外部函数的形式参数,但是如果内部函数想要修改外部函数的形式参数那就必须使用nonlocal关键字。

多个闭包是内存隔离的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def wrapper(name):
def message(content):
print(f'{name}: {content}')

print(f'内部函数引用的地址为:', id(message))
return message


func_1 = wrapper('安娜')
func_2 = wrapper('双双')

# 闭包多次运行返回的内部函数的地址是不一样的,所以闭包具有内存隔离的特性,与面向对象中的实例对象类似
print(id(func_1)) # 2610767972528
print(id(func_2)) # 2610767970944