一、闭包
1、什么是闭包
# 定义一个函数 def test(number): """ 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量, 同时,外部函数的返回值是内部函数的引用 那么将这个函数(内部定义的那个函数)以及用到的一些变量称之为闭包 """ def test_in(number_in): print("in test_in 函数, number_in is %d" % number_in) return number + number_in # 其实这里返回的就是闭包的结果 return test_in # 给test函数赋值,这个20就是给参数number ret = test(20) # 注意这里的100其实是给test函数内部定义的test_in函数的参数number_in赋值 # ret是test函数的返回值,即返回的是test函数内部的定义的test_in函数的引用 print(ret(100)) #注 意这里的200其实给参数number_in print(ret(200))
二、装饰器
1、先理解下面代码
#### 第一波 #### def foo(): print('foo') foo # 表示是函数的引用 foo() # 表示执行foo函数 #### 第二波 #### def foo(): print('foo') foo = lambda x: x + 1 foo() # 执行lambda表达式,而不再是原来的foo函数,因为foo这个名字被重新指向了另外一个匿名函数 # 以上代码是将lambda表达式赋值给了foo变量,此时,执行foo(),代表的是执行lambda表达式
函数名仅仅是个变量,只不过指向了定义的函数而已,所以才能通过 函数名()调用;如果 变量被修改了,即函数名=xxx ,那么当在执行 函数名() 时,调用的就不是之前的那个函数了,而是被赋值之后的函数
2、装饰器
使用闭包引入装饰器概念
def validation(fun): # 定义一个内部函数 def doValidation(): # 执行前置校验 print("放在 fun() 之前的内容是属于前置校验") # 执行fun函数 fun() # 执行后置校验 print("放在 fun() 之后的内容是属于后置校验") # 外部函数返回值是内部函数的引用 return doValidation def test(): print("test方法中加入校验") """ 实例化外部函数,参数是其他函数(test函数)的引用 由于外部函数(validation)中还有一个函数定义, 因此,实例化外部函数的时候,会定义一个内部函数,返回的是内部函数的引用 而由于,在内部函数中使用其他函数(test函数)的引用来实例化了一个其他函数(test函数)对象, 因此,实例化内部函数的时候,会进行其他函数(test函数)的实例化操作 """ test = validation(test) # 此时的test是内部函数的引用 """ 执行内部函数,由于内部函数中其他函数(test)的实例化操作 因此,在内部函数中所执行的代码(本例中为打印操作)可以放在其他函数(test)前或者后进行操作 即:达到了在执行其他函数前(或者后)进行校验的目的 """ test() """ 运行结果: 放在 fun() 之前的内容是属于前置校验 test方法中加入校验 放在 fun() 之后的内容是属于后置校验 """
使用装饰器来进行上述操作的代码:
def validation(fun): # 定义一个内部函数 def doValidation(): # 执行前置校验 print("放在 fun() 之前的内容是属于前置校验") # 执行fun函数 fun() # 执行后置校验 print("放在 fun() 之后的内容是属于后置校验") # 外部函数返回值是内部函数的引用 return doValidation @validation def test(): print("test方法中加入校验") """ 实例化外部函数,参数是其他函数(test函数)的引用 由于外部函数(validation)中还有一个函数定义, 因此,实例化外部函数的时候,会定义一个内部函数,返回的是内部函数的引用 而由于,在内部函数中使用其他函数(test函数)的引用来实例化了一个其他函数(test函数)对象, 因此,实例化内部函数的时候,会进行其他函数(test函数)的实例化操作 ⭐⭐⭐在其他函数上使用 @外部函数名 ,这种方式可以替代以下代码来进行test方法执行前后的校验 test = validation(test) # 返回值是内部函数的引用 """ """ 执行内部函数,由于内部函数中其他函数(test)的实例化操作 因此,在内部函数中所执行的代码(本例中为打印操作)可以放在其他函数(test)前或者后进行操作 即:达到了在执行其他函数前(或者后)进行校验的目的 """ test() """ 运行结果: 放在 fun() 之前的内容是属于前置校验 test方法中加入校验 放在 fun() 之后的内容是属于后置校验 """
解释:在方法上加上 @其他方法名 的方式即为装饰器的使用,而其他方法是一个包含了内部函数的一个函数,在内部函数中有方法的实例化操作,这种方式就达到了装饰器的效果
3、对带有参数的方法进行装饰器
不使用装饰器的写法:
def validation(fun): # 定义一个内部函数 def doValidation(args): # 执行前置校验 print("放在 fun() 之前的内容是属于前置校验") # 执行fun函数 fun(args) # 执行后置校验 print("放在 fun() 之后的内容是属于后置校验") # 外部函数返回值是内部函数的引用 return doValidation def test(args): print("test方法中加入校验 %s" % args) test = validation(test) # 返回值是是内部函数的引用 test(100)
使用装饰器的写法:
def validation(fun): # 定义一个内部函数 def doValidation(args): # 执行前置校验 print("放在 fun() 之前的内容是属于前置校验") # 执行fun函数 fun(args) # 执行后置校验 print("放在 fun() 之后的内容是属于后置校验") # 外部函数返回值是内部函数的引用 return doValidation @validation def test(args): print("test方法中加入校验 %s" % args) # test = validation(test) # 返回值是是内部函数的引用 test(100)
4、不定长参数的函数装饰器
def validation(fun): # 定义一个内部函数 def doValidation(*args, **kwargs): # 执行前置校验 print("放在 fun() 之前的内容是属于前置校验") # 执行fun函数 fun(*args, **kwargs) # 执行后置校验 print("放在 fun() 之后的内容是属于后置校验") # 外部函数返回值是内部函数的引用 return doValidation @validation # test = validation(test) 返回值是是内部函数的引用 def test(num, *args, **kwargs): print("test方法中参数1 %s" % num) print("test方法中参数2 : " , args) print("test方法中参数3 : " , kwargs) test(100) print("-" * 50) test(100, 200) print("-" * 50) test(100, 200, 300, name='李四') """ 运行结果: 放在 fun() 之前的内容是属于前置校验 test方法中参数1 100 test方法中参数2 : () test方法中参数3 : {} 放在 fun() 之后的内容是属于后置校验 -------------------------------------------------- 放在 fun() 之前的内容是属于前置校验 test方法中参数1 100 test方法中参数2 : (200,) test方法中参数3 : {} 放在 fun() 之后的内容是属于后置校验 -------------------------------------------------- 放在 fun() 之前的内容是属于前置校验 test方法中参数1 100 test方法中参数2 : (200, 300) test方法中参数3 : {'name': '李四'} 放在 fun() 之后的内容是属于后置校验 """
5、带有返回值的函数的装饰器
带有返回值的函数的装饰器亦是通用装饰器(可变参数,有返回值的装饰器)的写法:
def validation(fun): # 定义一个内部函数 def doValidation(*args, **kwargs): # 执行前置校验 print("放在 fun() 之前的内容是属于前置校验") # 执行fun函数 return fun(*args, **kwargs) # 执行后置校验 print("放在 fun() 之后的内容是属于后置校验") # 外部函数返回值是内部函数的引用 return doValidation @validation # test = validation(test) 返回值是是内部函数的引用 def test(num, *args, **kwargs): print("test方法中参数1 %s" % num) print("test方法中参数2 : " , args) print("test方法中参数3 : " , kwargs) return "OK" ret = test(100) print(ret) print("-" * 50) ret = test(100, 200) print(ret) print("-" * 50) ret = test(100, 200, 300, name='李四') print(ret) """ 运行结果: 放在 fun() 之前的内容是属于前置校验 test方法中参数1 100 test方法中参数2 : () test方法中参数3 : {} OK -------------------------------------------------- 放在 fun() 之前的内容是属于前置校验 test方法中参数1 100 test方法中参数2 : (200,) test方法中参数3 : {} OK -------------------------------------------------- 放在 fun() 之前的内容是属于前置校验 test方法中参数1 100 test方法中参数2 : (200, 300) test方法中参数3 : {'name': '李四'} OK """
6、多个装饰器对一个函数进行装饰
def zhuangshi_1(fun): print("定义装饰1") # 定义一个内部函数 def neibu_1(*args, **kwargs): # 执行前置校验 print("执行 zhuangshi_1 中的装饰内容") # 执行fun函数 return fun(*args, **kwargs) # 外部函数返回值是内部函数的引用 return neibu_1 def zhuangshi_2(fun): print("定义装饰2") # 定义一个内部函数 def neibu_2(*args, **kwargs): # 执行前置校验 print("执行 zhuangshi_2 中的装饰内容") # 执行fun函数 return fun(*args, **kwargs) # 外部函数返回值是内部函数的引用 return neibu_2 @zhuangshi_1 @zhuangshi_2 def test(): pass test() """ 运行结果: 定义装饰2 定义装饰1 执行 zhuangshi_1 中的装饰内容 执行 zhuangshi_2 中的装饰内容 解释: 定义装饰器的时候,先执行离方法最近的装饰器的定义 执行装饰器的时候,先执行最上层的装饰器 """
7、多个装饰器装饰一个函数的应用
def html_1(func): def td(): return "<td>" + func() +"</td>" return td def html_2(func): def p1(): return "<p1>" + func() + "</p1>" return p1 @html_1 @html_2 def test(): return "hello world" print(test()) """ 运行结果: <td><p1>hello world</p1></td> """
8、带有参数的装饰器
def parent(arg): def validation(func): def call_func(*args, **kwargs): if arg == 1: print("level 1") elif arg == 2: print("level 2") return func() return call_func return validation """ ⭐⭐⭐:带有参数的装饰器调用的时候: 首先会将参数当作实参,传递到装饰器中,进行第一层函数的调用,并返回第二层函数的引用; 然后,将第二层函数的引用当作真正的装饰器,进行装饰 以下调用中,首先@parent(1)会先执行parent方法,把参数1传递进去,返回的是validation的引用 然后,使用validation作为真正的装饰器,对test1方法进行装饰 """ @parent(1) def test1(): return "OK" test1() @parent(2) def test2(): return "OK" test2()
9、用类对函数进行装饰
class Test(object): def __init__(self, func): self.func = func def __call__(self): print("对函数进行装饰的方法") return self.func() @Test def demo(): return "呵呵" print(demo())