创作不易,来了的客官点点关注,收藏,订阅一键三连❤😜
前言
“人生苦短,我用python”,我是一个即将毕业的大学生,超超。如果你也爱python,不妨跟着萌新超超一起学习python,拿下python,一起加油,共同努力,拿到理想offer!
系列文章目录
python | 面向对象(四):python的自省、元类、抽象基类
Python | python中的下划线,常用魔术方法与属性
Python | 经典类与新式类,静态方法、类方法与实例方法详解!
概述
本期内容是python中的闭包和装饰器知识,面试中常考知识点,万字详解,拿下它!
目录
闭包
什么是闭包
• 在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。
• 闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。
• 在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
闭包的概念很简单:一个可以引用在函数闭合范围内变量的函数。即"内部函数",只有那个内部函
数才有所谓的__closure__属性。
生命周期
# a=1 定义时开始,执行完结束。生命周期定义了程序的开始与结束
def func1():
a = 10
print(f" test {a}")
func1()
# 注:函数调用完 a就释放了,生命周期是函数调用的时间
# print(a)
# 注:打印不出来
#变量解析原则: LEGB原则:local enclosing global build-in
def outer(x):
a = 300
def inner():
print(x + a)
return inner # 返回inner函数
d = outer(10) # 此时d是inner函数
d() # d()返回inner()的结果:310
print(dir(d))
print(d.__closure__) # closure里保存了两个整数
满足闭包的条件
1.必须有一个内嵌函数
2.内函数必须引用外函数的变量
3.外函数必须返回内函数
闭包的使用
• 形成闭包之后,闭包函数会获得一个非空的__closure__属性(对比我们最后的函数test,test是一个不具备闭包的函数,它的__closure__属性是None),这个属性是一个元组。
• 元组里面的对象为cell对象,而访问cell对象的cell_contents属性则可以得到闭包变量的当前值(即上一次调用之后的值)。
• 而随着闭包的继续调用,变量会再次更新。
• 所以可见,一旦形成闭包之后,python确实会将__closure__和闭包函数绑定作为储存闭包变量的场所。
def outer():
tmp_list = []
def inner(name):
tmp_list.append(1)
print("%s -- %s"%(name,tmp_list))
return inner
d1 = outer()
d1("d1")
# 输出结果
# d1 -- [1]
d1("d1")
# 输出结果
# d1 -- [1, 1]
d2 = outer() # 每次调用函数都会重新执行
d2("d2")
# 输出结果
# d2 -- [1]
每次调用外函数,都会重新执行,创建一个新的tmp_list和inner,代码虽然一样,但是创建不同对象
def outer():
fs = []
for i in range(5):
def inner():
return i*i
fs.append(inner)
return fs
f1,f2,f3,f4,f5 = outer() # 执行完outer后,i的值为4了
print(f1())
# 输出结果:16
print(f2())
# 输出结果:16
print(f3())
# 输出结果:16
print(f4())
# 输出结果:16
print(f5())
# 输出结果:16
闭包的好处
• 闭包不是必须的。
• 没了闭包,python的功能一点不会被影响
• 有了闭包,只是提供给你一种额外的解决方案。
装饰器
什么是装饰器
• 装饰器的本质是闭包,在不改变函数或类的源代码基础上,添加额外功能
• 装饰器的本质是闭包,它需要一个callable对象(函数,类)作为参数传入
• 装饰器是这样一种设计模式:如果一个类(函数)希望添加其他类(函数)的一些功能,
而不希望通过继承或是直接修改源代码实现,那么可以使用装饰器模式。(不改变源代码的情况下增加新的功能)
• 简单来说Python中的装饰器就是指某些函数或其他可调用对象,以函数或类作为可选输入参数,然后返回函数或类的形式。通过这个在Python2.6版本中被新加入的特性可以用来实现装饰器设计模式。
• 装饰器就是一个可以接受调用也可以返回调用的函数,该函数接受被装饰的函数作为其位置参数。装饰器通过使用该参数来执行某些操作,然后返回原始参数或一些其他的调用
• 函数也是对象,也可以当做参数传递
装饰器的用途
我们可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。
例