1.闭包
闭包的概念:
闭包是函数式编程的一个重要的语法结构,维基百科上对于闭包这个概念是这么解释的:“在计算机科学中,闭包(closure)是词法闭包(lexical closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。”
举个例子:
def funX(x): # 这个函数就是一个闭包 def funY(y): return x * y return funY temp = funX(8) print(temp(5)) # 40
通过上面的例子理解闭包的概念:如果在一个内部函数里(funY()就是这个内部函数)对在外部作用域(但不是在全局作用域)的变量进行引用(x就是被引用的变量,x在外部作用域funX()函数里面,但不在全局作用域里),则这个内部函数就是一个闭包
那为什么要使用闭包呢?看起来闭包似乎是一种高级但是并没什么用的技巧。其实,闭包概念的引入是为了尽可能地避免使用全局变量,闭包允许将函数与其所操作的某些数据(环境)关联起来,这样外部函数就为内部函数构成了一个封闭的环境。这一点与面向对象编程的概念是非常类似的
2.装饰器
Python中装饰器(decorator)的功能是将被装饰的函数当作参数传递给与装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数
要想彻底理解装饰器,我们需要看下面的这个例子:
def eat(): print("开始") print("开吃") print("结束")
这样的代码不符合“一个函数只做一件事情”的原则,刚学过的闭包就可以助你一臂之力:
def eat(): print("开吃") def log(func): def wrapper(): print("开始") func() print("结束") return wrapper eat = log(eat) eat() # 开始 # 开吃 # 结束
log(eat)将eat函数作为参数传递给log(),由于wrapper()是log()的闭包,所以它可以访问log()的局部变量func,也就是刚刚传递进来的eat,因此,执行func()与执行eat()是一个效果。这样一来,问题就解决了!既没有修改eat()函数里面的逻辑结构,也不会给主程序带来太多的干扰项。不过这个eat = log(eat)看着总有些别扭,能不能改善一下呢?
可以,Python因此发明了“@语法糖”来解决这个问题。所谓语法糖(Syntactic sugar),就是在计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。
有了“@语法糖”,上面的代码就可以这么写:
def log(func): def wrapper(): print("开始") func() print("结束") return wrapper @log def eat(): print("开吃") eat() # 开始 # 开吃 # 结束
这样就省去了手动将eat()函数传递给log()再将返回值重新赋值的步骤
那么,来看下一个问题:
如果eat()函数有参数怎么办?
别忘了,我们还有参数打包操作:
def log(func): def wrapper(*params): print("开始") func(*params) print("结束") return wrapper @log def eat(name): print(name + "开吃") eat("dahezhiquan") # 开始 # dahezhiquan开吃 # 结束
到这里,一个完美的装饰器程序就写好啦!🥞