python闭包与装饰器
闭包
在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数。
示例:
#----------------------------------
name='tom'
def func():
name='jack'
def bar():
print(name)
return bar
f = func() # f = bar
f() # 调用bar()
#输出结果:
jack
上述代码运行结果打印的是jack而不是tom,bar这个函数就是闭包函数。
闭包函数属性:
闭包函数是内部函数
包含对外部作用域而非全局作用域的引用
闭包函数特点:
自带作用域
延迟计算
注意:
函数的作用域关系在函数定义阶段就已经固定,与调用位置无关,无论函数在何处调用,都需要回到定义阶段去找对应的作用域关系。
查看一个函数是否是闭包函数可以使用__closure__方法:
name='tom'
def func():
name='jack'
def bar():
print(name)
return bar
f = func() # f = bar
f() # 调用bar()
print(f.__closure__) #如果是闭包函数返回引用的外部作用域对象
print(f.__closure__[0].cell_contents)
#返回闭包函数引用外部作用域的值,[0]就是取第一个对象的值,有多个也可以这样取出
总结
闭包函数的基本形式:
# def 外部函数名():
# 内部函数需要的变量
# def 内部函数():
# 引用外部变量
# return 内部函数
装饰器
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能,使用装饰器能够使用原函数名调用实现除了原来功能之外的扩展功能。
定义比较抽象,下面举个例子:
def deco(func):
def wrapper(*args,**kwargs): #这个就相当于是修饰后的新函数
print('before')
res = func(*args,**kwargs) #意味着传入函数可以接收可变长参数
print('after')
return res #这个返回值就是传入函数的返回值
return wrapper
@deco #将下面的foo作为参数传入deco(),等同于foo = deco(foo),这时候的foo = wrapper
def foo(x,y):
print('this is foo')
return x+y
foo(2,3) #调用foo其实就是执行wrapper
# print(foo(2,3)) #测试返回值
装饰器的原则
不能修改被装饰的函数的源代码
不能修改被装饰的函数的调用方式
装饰器的作用
在不修改被装饰对象源代码以及调用方式的前提下为期添加新功能
多个装饰器调用
@auth #foo = auth(time(foo))
@time #foo = time(foo)
def foo():
pass
调用顺序可以理解为:先调用auth,再调用time,再调用foo。总结就是从外到内(从上往下)执行,判断调用关系就是从内到外。相当于给foo函数增加了time功能和auth两个功能,包了两层,一层一个功能。
有参装饰器
上面说的装饰器函数都是无参装饰器,还有一种是有参装饰器,有参装饰器其实就是在无参装饰器函数外面再包了一个变量。
示例:
def deco(type):
def auth(func):
def wrapper(*args,**kwargs):
if type == 'file':
print('file auth')
res = func(*args,**kwargs)
return res
elif type == 'ldap':
print('ldap auth')
elif type == 'mysql':
print('mysql auth')
else:
print('other auth')
return wrapper
return auth
@deco('file') #执行deco('file')返回auth,然后@auth,index = auth(index) 所以最终执行index()还是wrapper()函数,不过不同的是包括了type='file'
def index():
print('welcome to index')
index()
#执行结果:
file auth
welcome to index