闭包 python_Python基础入门(闭包)

通过解决一个需求问题来了解闭包。

这个需求是这样的,我们需要一直记录自己的学习时间,以分钟为单位。就好比我学习了 2 分钟,就返回 2 ,然后隔了一阵子,我学习了 10 分钟,那么就返回 12 ,像这样把学习时间一直累加下去。

面对这个需求,我们一般都会创建一个全局变量来记录时间,然后用一个方法来新增每次的学习时间,通常都会写成下面这个形式:

time = 0

def insert_time(min):

time = time + min

return  time

print(insert_time(2))

print(insert_time(10))

其实,这个在 Python 里面是会报错的。会报如下错误: UnboundLocalError: local variable 'time' referenced before assignment

那是因为,在 Python 中, 如果一个函数使用了和全局变量相同的名字且改变了该变量的值,那么该变量就会变成局部变量 ,那么就会造成在函数中我们没有进行定义就引用了,所以会报该错误。

我们可以使用 global 关键字,具体修改如下:

time = 0

def insert_time(min):

global  time

time = time + min

return  time

print(insert_time(2))

print(insert_time(10))

输出结果如下:

2

12

可是啊,这里使用了全局变量,我们在开发中能尽量避免使用全局变量的就尽量避免使用。因为不同模块,不同函数都可以自由的访问全局变量,可能会造成全局变量的不可预知性。比如程序员甲修改了全局变量

time 的值,然后程序员乙同时也对 time 进行了修改,如果其中有错误,这种错误是很难发现和更正的。

这时候我们使用闭包来解决一下,先直接看代码:

time = 0

def study_time(time):

def insert_time(min):

nonlocal  time

time = time + min

return time

return insert_time

f = study_time(time)

print(f(2))

print(time)

print(f(10))

print(time)

输出结果如下:

这里最直接的表现就是全局变量 time 至此至终都没有修改过,这里还是用了 nonlocal 关键字,表示在函数或其他作用域中使用外层(非全局)变量。那么上面那段代码具体的运行流程是怎样的。我们可以看下下图:

这种内部函数的局部作用域中可以访问外部函数局部作用域中变量的行为,我们称为: 闭包。更加直接的表达方式就是,当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。

有没有什么办法来验证一下这个函数就是闭包呢?

有的,所有函数都有一个 __closure__ 属性,如果函数是闭包的话,那么它返回的是一个由 cell 组成的元组对象。cell 对象的 cell_contents 属性就是存储在闭包中的变量。看代码:

2

0

12

0

这里最直接的表现就是全局变量 time 至此至终都没有修改过,这里还是用了 nonlocal 关键字,表示在函数或其他作用域中使用外层(非全局)变量。那么上面那段代码具体的运行流程是怎样的。我们可以看下下图:3c90b09a797079d58622b43ebec415060715fd1b.png

这种内部函数的局部作用域中可以访问外部函数局部作用域中变量的行为,我们称为: 闭包。更加直接的表达方式就是,当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。

有没有什么办法来验证一下这个函数就是闭包呢?

有的,所有函数都有一个 __closure__ 属性,如果函数是闭包的话,那么它返回的是一个由 cell 组成的元组对象。cell 对象的 cell_contents 属性就是存储在闭包中的变量。看代码:

ime = 0

def study_time(time):

def insert_time(min):

nonlocal  time

time = time + min

return time

return insert_time

f = study_time(time)

print(f.__closure__)

print(f(2))

print(time)

print(f.__closure__[0].cell_contents)

print(f(10))

print(time)

print(f.__closure__[0].cell_contents)

打印结果为:

(,)

2

0

2

12

0

12

从打印结果可见,传进来的值一直存储在闭包的 cell_contents 中,因此,这也就是闭包的最大特点,可以将父函数的变量与其内部定义的函数绑定。就算生成闭包的父函数已经释放了,闭包仍然存在。

闭包的过程其实好比类(父函数)生成实例(闭包),不同的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时创建,一般程序执行完毕后作用域才释放,因此对一些需要重用的功能且不足以定义为类的行为,使用闭包会比使用类占用更少的资源,且更轻巧灵活。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值