闭包
定义双层嵌套函数,内层函数可以访问外层函数的变量,将内层函数作为外层函数的返回,此内层函数就是闭包函数
通过全局变量来定义变量时,尽管功能实现是OK的。但是仍有问题:
- 代码在命名空间上(变量定义)不够干净、整洁
- 全局变量有被修改的风险
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
闭包注意事项
优点,使用闭包可以让我们得到:
- 无需定义全局变量即可实现通过函数,持续的访问、修改某个值
- 闭包使用的变量的作用于函数内,难以被错误的调用修改
缺点:
- 由于内部函数持续引用函数的值,所以会导致这一部分内存空间不被释放,一直占用内存
# 简单的闭包
def outer(logo):
def inner(msg):
print(f"<{logo}>{msg}<{logo}>")
return inner
fn1 = outer("黑马程序员")
fn1("大家好")
fn2 = outer("传智教育")
fn2("学Python")
<黑马程序员>大家好<黑马程序员>
<传智教育>学Python<传智教育>
修改外部函数变量的值
需要使用nonlocal关键字修饰外部函数的变量才可在内部函数中修改它
# 简单的闭包
def outer(num1):
def inner(num2):
nonlocal num1
num1 += num2
print(num1)
return inner
fn = outer(10)
fn(10)
fn(10)
fn(10)
20
30
40
# 使用闭包实现ATM小案例
def account_create(initial_account=0):
def atm(num, deposit=True):
nonlocal initial_account
if deposit:
initial_account += num
print(f"存款:+{num}, 账户余额:{initial_account}")
else:
initial_account -= num
print(f"存款:-{num}, 账户余额:{initial_account}")
return atm
atm = account_create()
atm(100)
atm(200)
atm(100)
atm(200, False)
存款:+100, 账户余额:100
存款:+200, 账户余额:300
存款:+100, 账户余额:400
存款:-200, 账户余额:200
装饰器
装饰器其实也是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能
def sleep():
import random
import time
print("睡眠中.......")
time.sleep(random.randint(1, 5))
希望给sleep函数,增加一个功能:
- 在调用sleep前输出:我要睡觉了
- 在调用sleep后输出:我起床了
# 装饰器的一般写法(闭包写法)
def outer(func):
def inner():
print("我要睡觉了")
func()
print("我起床了")
return inner
def sleep():
import random
import time
print("睡眠中.......")
time.sleep(random.randint(1, 5))
fn = outer(sleep)
fn()
我要睡觉了
睡眠中.......
我起床了
# 装饰器的语法糖写法,在不改变sleep函数的前提下,增加了inner函数内部的功能
def outer(func):
def inner():
print("我要睡觉了")
func()
print("我起床了")
return inner
@outer
def sleep():
import random
import time
print("睡眠中.......")
time.sleep(random.randint(1, 5))
sleep()
我要睡觉了
睡眠中.......
我起床了