Python闭包和装饰器

参考:

https://zhuanlan.zhihu.com/p/453787908

https://www.bilibili.com/video/BV1JW411i7HR/?spm_id_from=333.337.search-card.all.click&vd_source=e44be2a53e5c6a4338b789d3833698fc

什么是闭包?

简单来说就是,在一个函数f1中又定义了一个函数f2,f2构成了闭包,一般来说f2会使用f1中的某些变量

def func():#外部函数
    a = 1  #外部函数作用域里面的变量 
    print("this is func.")
    def func1(num):#内部函数 
    	print("this is func1")
        print(num + a)
        return func1
    
if __name__ == '__main__':
	#func()#运行外部函数,内部面数就被创建了
    var = func()#创建过程在funC国数的执行过程中
    #var == funcl
    var(3) #这样处理后,func的局部变量a会随着var一直存在于内存之中直到var被GC回收或用户删除	

定义

维基百科的严肃定义:

在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。

解读一下就是:

  • 定义:闭包就是能够读取其外部函数变量的一个函数
  • 作用1:将外层函数(这个“外层”是相对于闭包函数来说的)内的局部变量和外层函数的外部连接起来的一座桥梁
  • 作用2:将外层函数的变量持久地保存在内存中

举例

再举一个例子认识闭包对于持久化局部变量的作用

mylist = [1,2,3,4,5]
def func(obj):
    print('func:', obj)
    def func1():
        obj[0] += 1
        print('func1:', obj)
    return func1

if __name__ == '__main__':
    var =func (mylist)
    var()
    #var: obj print( 'funcl: ' ,obj)
func:  [1,2,3,4,5]
func1: [2,2,3,4,5]
func1: [3,2,3,4,5]
func1: [4,2,3,4,5]
[Finished in 0.1s]

什么是装饰器?

装饰器是Python中的一种语法糖,用于修饰一个函数,使其具有额外的某些功能

@func1
def func():
	print('aaa')
#不影响原有面数的功能,还能添加新的功能

模板

一般来说写一个装饰器的模板如下

def func1(func) :
    ...
    def func2():
        ...
    	return func
    
	return func2


@func1
def xxx():
	pass

装饰器使用过程分析

def func1(func):#外部闭包函数的参数是被装饰的面数对象
    def func2():
    	print('aaabbb ')
    	return func()#返回了外部面数接收的被装饰面数的调用
	return func2
#func1() takes 0 positional arguments but 1 was given

#return func#返回了面数对象
#return func()#返回的是一个函数调用
#func1(myprint)()#接收被装饰的函数作为参数,而且还要继续调用一次
#func2() -> print('aaabbb') -> return myprint()

@func1
def myprint():
	print("你好,我是print')
          
if __name__ == '__main__':
		myprint()#func1(myprint)()

上述代码中,func1作为装饰器修饰函数myprint(),工作步骤如下:

​ ①调用func1函数,将myprint函数作为参数传入

​ ②调用func1的内部函数(闭包)func2,func2打印语句并使用了传入func1的参数myprint函数,将其作为返回值返回

​ ③结束

总结一下就是:整个过程中,我们多运行了一个闭包,这个闭包就是修饰器func1附加给myprint函数的功能

例子

1、含参数的装饰器
def arg_func(sex):
    def func1(b_func) :
        def func2():
            if sex == 'man':
            	print('你不可以生娃")
            if sex == 'woman':
            	print('你可以生娃')
            return b_func()
        return func2
    return func1
                      
#arg_func(sex= ' man ')()() --> func1#func1() --> func2
#func2() >('你不可以生娃') or print( '你可以生娃') 	b_func()
@arg_func(sex = 'man')
def man():
	print("好好上班.')
@arg_func (sex = 'woman ')
def woman():
	print(好好上班.')
          
if __name__ == '__main__':
	man ()
    woman()      

含参的装饰器需要再为装饰器函数再套一层来接受参数

2、被修饰函数带参数
def func1( func) :
    def func2(x, y):
    	print(x, y)
        x += 5
    	y += 5
    	return func(x, y)
    
    return func2

@func1
def mysum(a, b):
	print(a + b)
    
if __name__ == '__main__':
    mysum(1,2)

被装饰的函数带参数:只需要在最内部函数传入参数即可

常用于某些数学模块的编写