一、闭包
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())