装饰器是什么
‘装饰’指被装饰对象添加新的功能,‘器’代指器具/工具,装饰器与被装饰对象均可是可以任意调用的对象。 装饰器是由 名称空间 函数对象 闭包函数组合使用的一种方法
装饰器的用途
装饰器核心: 能够在不改变被“装饰对象内部代码”和“原有调用方式”的基础上给被装饰对象添加额外的功能
装饰器的实现
装饰器可以分为: 无参装饰器和有参装饰器两种,两者实现原理一样
无参装饰器实现过程
1.给函数添加统计执行时间的功能
import time
def outer ( func) :
def get_time ( ) :
start_time = time. time( )
func( )
end_time = time. time( )
print ( '函数运行时间:%s' % ( end_time - start_time) )
return get_time
def func1 ( ) :
print ( 'from func1' )
func1 = outer( func1)
func1( )
这时,我们通过上方代码成功给func1添加了一个新功能,但还没完,我们可以发现,若函数是一个有参函数,便无法正常运行
2.解决函数参数问题
import time
def outer ( func) :
def get_time ( * args, ** kwargs) :
start_time = time. time( )
func( * args, ** kwargs)
end_time = time. time( )
print ( '函数运行时间:%s' % ( end_time - start_time) )
return get_time
def func1 ( a, b) :
print ( 'from func1 %s:%s' % ( a, b) )
func1 = outer( func1)
func1( 11 , 22 )
通过前面学习的可变长参数,就能够将函数参数问题完美解决,并且不管该装饰器所装饰的对象是否需要参数,需要多少参数,运行都是没有问题 这时我们还忽略的一个问题,原函数返回值问题,也是需要我们解决
3. 解决返回值问题
import time
def outer ( func) :
def get_time ( * args, ** kwargs) :
start_time = time. time( )
res = func( * args, ** kwargs)
end_time = time. time( )
print ( '函数运行时间:%s' % ( end_time - start_time) )
return res
return get_time
def func1 ( a, b) :
print ( 'from func1 %s:%s' % ( a, b) )
return a b
func1 = outer( func1)
func1( 11 , 22 )
到了这一步,我们已经基于开放封闭原则,在不修改被装饰对象func1的源代码和调用方式的前期下,给func1添加了一个新功能,实现了一个简单的无参装饰器 该装饰器还可以用来装饰其他带参数或者不带参数的函数
4.无参装饰器固定模板
def outer ( func) :
def inner ( * args, ** kwargs) :
print ( '执行函数之前可以添加的额外功能' )
res = func( * args, ** kwargs)
print ( '执行函数之后可以添加的额外功能' )
return res
return inner
装饰器语法糖
我们在使用用装饰器,方式一: 'func1 = outer(func1)' 这种形式是不可缺少的,如果装饰器使用过多,不可避免的会照成代码冗余,为了解决这个问题,python解释器提供了一种专门装饰器语法来取代
@outer
使用注意事项:
"""
装饰器语法糖是写规范
语法糖必须紧贴在被装饰对象的上方
装饰器语法糖内部原理
会自动将下面紧贴着的被装饰对象名字当做参数传给装饰器函数调用
"""
并且如果我们有多个装饰器,可以叠加多个
@deco3
@deco2
@deco1
def index ( ) :
pass
上述代码语义如下:
index= deco3( deco2( deco1( index) ) )
'''
定义自下而上 运行自上而下
'''
有参装饰器的实现
基于无参装饰器实现原理,我们可以再来实现一个用来为被装饰对象添加认证功能的装饰器,实现基本形式如下
def login_auth ( func) :
def auth ( * args, ** kwargs) :
if source_data == 'file' :
print ( 'file文件获取' )
elif source_data == 'MySQL' :
print ( 'MySQL数据库获取' )
elif source_data == 'postgreSQL' :
print ( 'postgreSQL数据库获取' )
else :
print ( '用户名或密码错误 无法执行函数' )
return auth
通过上述代码 我们可以发现,auth函数内还需要一个source_data参数。 而此时不管是login_auth函数还是auth函数都无法直接传参,因此我们剩下一种办法,在login_auth函数外面再包一层,专门用来传参
def outer ( source_data) :
def login_auth ( func) :
def auth ( * args, ** kwargs) :
if source_data == 'file' :
print ( 'file文件获取' )
elif source_data == 'MySQL' :
print ( 'MySQL数据库获取' )
elif source_data == 'postgreSQL' :
print ( 'postgreSQL数据库获取' )
else :
print ( '用户名或密码错误 无法执行函数' )
return auth
return login_auth
@outer ( 'file' )
def index ( ) :
print ( 'from index' )
@outer ( 'MySQL' )
def home ( ) :
print ( 'from home' )
index( )
home( )
有参装饰器模板
def outer ( 参数1 ,参数2 ) :
def werper ( func) :
def inner ( * args, ** kwargs) :
print ( '执行函数之前可以添加的额外功能' )
res = func( * args, ** kwargs)
print ( '执行函数之后可以添加的额外功能' )
return res
return inner
return werper
装饰器修复技术
我们可以用help(函数名)来查看函数文档注释,但对于被装饰之后的函数,查看的文档注释并不是原文档注释
@timer
def home ( name) :
time. sleep( 3 )
print ( 'Welcome to the home page' , name)
print ( help ( home) )
'''
打印结果:
Help on function inner in module __main__:
inner(*args, **kwargs)
None
'''
解决办法(装饰器究极模板)
from functools import wraps
def outer ( func) :
@wraps ( func)
def inner ( * args, ** kwargs) :
print ( '执行函数之前可以添加的额外功能' )
res = func( * args, ** kwargs)
print ( '执行函数之后可以添加的额外功能' )
return res
return inner
@outer
def index ( ) :
print ( 'from index' )
print ( index)
help ( index)
到此,我们用help查看函数名属性和注释就是原函数的内容了