函数闭包的学习
一、闭包的概念,作用,条件
作用:可以保存外部函数的变量
形成条件:
1 函数嵌套 2 内部函数用了外部函数的变量或者参数
3 外部函数返回了内部函数(是返函数名,不带括号)
这个使用了外部函数变量的内部函数称为闭包。
口诀:函数嵌套,内用外参,外返内名。
例1:
def outer_function(x):
def inner_function(y):
return x + y # 访问外部函数的局部变量 x
return inner_function
# 创建闭包函数
inner = outer_function(10)
result1 = inner(5) # 输出:15
例2:根据配置信息使用闭包实现不同人的对话信息。例如对话:
张三:到北京了吗?
李四:已经到了,放心吧。
def config_name(name):
def inner(msg):
print(f"{name}:{msg}")
return inner
tom=config_name("Tom")
jerry=config_name("Jerry")
tom("我们一起玩耍")
jerry("我不去")
tom("来嘛来嘛")
jerry("打死都不去")
实现方式2:
def create_conversation(person_name, *lines):
def conversation(partner_name):
for i, line in enumerate(lines):
if i % 2 == 0:
print(f"{person_name}: {line}")
else:
print(f"{partner_name}: {line}")
return conversation
# 创建对话闭包
tom_conversation = create_conversation("Tom", "我们一起玩耍", "来嘛来嘛", "打死都不去")
jerry_conversation = create_conversation("Jerry", "我不去", "来嘛来嘛")
# 执行对话闭包
tom_conversation("Jerry")
jerry_conversation("Tom")
例二分析:
这段代码定义了一个名为 `create_conversation` 的工厂函数,它用于创建对话闭包。这个工厂函数接收一个参与者的名字(`person_name`)和一系列对话行(`*lines`),然后返回一个新的函数 `conversation`。这个 `conversation` 函数设计用来模拟两个人之间的对话。
让我们逐步分析这段代码:
### **定义工厂函数**
```python
def create_conversation(person_name, *lines):
```
- `create_conversation` 函数接收一个参数 `person_name` 和一个可变参数 `*lines`,后者用于接收任意数量的对话行。
### **定义内部函数**
```python
def conversation(partner_name):
```
- 在 `create_conversation` 函数内部,定义了一个名为 `conversation` 的内部函数,它接收一个参数 `partner_name`,表示对话的另一方的名字。
### **对话逻辑**
```python
for i, line in enumerate(lines):
if i % 2 == 0:
print(f"{person_name}: {line}")
else:
print(f"{partner_name}: {line}")
```
- `conversation` 函数遍历 `lines` 中的所有对话行。
- 使用 `enumerate` 函数获取每个对话行的索引 `i` 和内容 `line`。
- 通过 `if i % 2 == 0` 判断当前行是否为 `person_name` 的发言。
- 根据是奇数行还是偶数行,交替打印两个参与者的发言。
### **返回内部函数**
```python
return conversation
```
- `create_conversation` 函数返回 `conversation` 函数。这意味着 `conversation` 函数现在是一个闭包,它捕获了 `person_name` 和 `lines` 变量。
### **创建对话闭包**
```python
tom_conversation = create_conversation("Tom", "我们一起玩耍", "来嘛来嘛", "打死都不去")
jerry_conversation = create_conversation("Jerry", "我不去", "来嘛来嘛")
```
- 调用 `create_conversation` 函数创建两个对话闭包:`tom_conversation` 和 `jerry_conversation`。
- 每个闭包都捕获了创建时传入的 `person_name` 和 `lines`。
### **执行对话闭包**
```python
tom_conversation("Jerry")
jerry_conversation("Tom")
```
- 分别调用 `tom_conversation` 和 `jerry_conversation` 函数,模拟两个人之间的对话。
- 传递 `partner_name` 参数给 `conversation` 函数,指定对话的另一方。
### **输出结果**
这段代码将输出以下对话:
```
Tom: 我们一起玩耍
Jerry: 我不去
Tom: 来嘛来嘛
Jerry: 打死都不去
Jerry: 我不去
Tom: 来嘛来嘛
Jerry: 打死都不去
```
- 对话在两个人之间交替进行,展示了闭包如何捕获和使用创建时传入的参数。
### **总结**
这段代码通过使用闭包(closure)机制,创建了两个模拟对话的函数。每个对话函数都捕获了创建时传入的参数,并在函数内部使用这些参数来模拟两个人的对话。这种方法可以有效地模拟具有状态的对话,其中对话的状态由闭包捕获的变量决定。
二、用nonlocal修改闭包内使用的外部变量:
def func_out():
num1 = 10
def func_inner():
nonlocal num1 # 声明 num1 是在外部作用域中定义的
num1 = 20 # 这将修改外部函数中的 num1 变量
# 内部要使用外部函数的变量
result = num1 + 10
print(result)
print("修改前的外部变量:", num1)
func_inner()
print("修改后的外部变量:", num1)
return func_inner
new_func = func_out()
new_func() # 调用返回的 func_inner 函数将被调用
结果:修改前的外部变量: 10
30
修改后的外部变量: 20
30
三、装饰器:
作用:对已有的函数进行额外的功能扩展