1、装饰器的理解
装饰器的目的是将一个函数嵌入到另一个函数中以供重用,不改变其结构,增加函数的使用,但又不写过多的冗余代码;
装饰器本质上是一个 Python 函数,它允许其他函数在不更改任何代码的情况下添加额外的功能。装饰器的返回值也是一个函数对象。
常用功能: 1、导入日志; 2.函数执行时间统计; 3、执行函数前的准备处理; 4.执行函数后清理函数; 5、权限验证; 6.缓存
2、实现原理与通用写法
我们可以从一个简单的记录函数运行时间的装饰器推导出一个通用的装饰器写法
import time
def timer(func):
'''
记录方法运行时间的装饰器
:param func: 方法
:return:函数对象
'''
def deco(*args, **kwargs):
startTime = time.time()
f = func(*args, **kwargs)
endTime = time.time()
msecs = (endTime - startTime) * 1000
print("time is %d ms" % msecs)
return f # 如果 func 有返回值得话,需要在此return回去,否则,默认返回值为 None,一般默认都返回
return deco
@timer
def test(parameter):
print("test is running!")
time.sleep(1)
return "Returned value" # 该函数有返回值,所以需要在 装饰器中的 deco 方法中 写返回值
t = test('aa')
print(t)
这是一个非常简单通用的记录时间的装饰器,所以导出一个通用装饰器的写法:
def func_name(func): # 自定义装饰器函数名
def deco(*args, **kwargs): # 将所有参数原封不动的进行传递
print("在这个分割线之上写函数运行前的操作")
# -----------分割线-----------
f = func(*args, **kwargs)
# -----------分割线-----------
print("在这个分割线之后,return之前,写函数运行后的操作")
return f # 如果 func 有返回值得话,需要在此return回去,否则,默认返回值为 None,一般默认都返回
return deco
@func_name
def test(parameter): # 8
print("test is running!")
time.sleep(1)
return "Returned value" # 该函数有返回值,所以需要在 装饰器中的 deco 方法中 写返回值
t = test('aa')
print(t)
ok 这里可以做装饰器,一般情况下可以满足需求。网上看那么多原理是浪费时间。我是偏向实用型的,实在不喜欢那么啰嗦,干脆就干了。
当然,在开发过程中,我们可能会遇到一些特殊情况,比如参数问题
1、给装饰器函数代参数(通用)
2.拆分计算执行函数的参数(例如:1000w数据,拆分成100次执行等)(自定义)
那就按顺序来
1、写一个代参数的装饰器
def logging(level):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print("[{level}]: enter function {func}()".format(level=level, func=func.__name__))
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@logging(level='INFO')
def say(something):
print("say {}!".format(something))
# 如果没有使用@语法,等同于
# say = logging(level='INFO')(say)
@logging(level='DEBUG')
def do(something):
print("do {}...".format(something))
if __name__ == '__main__':
say('hello')
do("my work")
发现:在上面的通用模板之上又多了一层! ! ! ,然后获取里面的参数!太简单!!!
2. 编写一个拆分参数的装饰器。这个有点自定义,不能像上面那样通用。例如:
def func_name(func): # 自定义装饰器函数名
def deco(*args, **kwargs): # 将所有参数原封不动的进行传递
print(args[0])
f_list = []
for i in range(0,args[0],100000):
print(i)
f_list.append(func(i))
# f_list # 这儿应该按照既定规则,继续对这个结果进行拼接,如果是写文件、入库等操作,可以不用return
return f_list # 这儿如果有返回值得话,应该是
return deco
@func_name
def test(parameter): # 8
print("test is running!")
time.sleep(1)
return "Returned value" # 该函数有返回值,所以需要在 装饰器中的 deco 方法中 写返回值
t = test(1000000)
print(t)
可见this的定制化程度略高,并不通用,但是我们已经意识到了自己的需求,所以我们最应该了解和学习的就是如何使用它! ! !
可见this的定制化程度略高,并不通用,但是我们已经意识到了自己的需求,所以我们最应该了解和学习的就是如何使用它! ! !
接下来介绍一下基于类的装饰器。那就是问题所在。我是一个实际的人。我不需要使用类装饰器。 ! !
装饰器函数其实就是这样一种接口约束,它必须接受一个可调用对象作为参数,然后返回一个可调用对象。一般可调用对象是Python中的函数,但也有例外。只要对象重载了 __call__() 方法,该对象就是可调用的。
class Test():
def __call__(self):
print 'call me!'
t = Test()
t() # call me
像 __call__ 这样带有下划线的方法在 Python 中被称为内置方法,有时也被称为魔法方法。覆盖这些魔法方法通常会改变对象的内部行为。上面的示例使类对象具有被调用的行为。
回到装饰器的概念,要求装饰器接受一个可调用对象,并返回一个可调用对象(不是很严格,详见下文)。
那么用类来实现也是可以的。我们可以让类构造函数__init__()接受一个函数,然后重载__call__()返回一个函数,这样也可以达到装饰器函数的效果。
class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print "[DEBUG]: enter function {func}()".format(
func=self.func.__name__)
return self.func(*args, **kwargs)
@logging
def say(something):
print "say {}!".format(something)
带参数的类装饰器
如果需要以类的形式实现带参数的装饰器,会比前面的例子稍微复杂一点。那么构造函数中接受的不是函数,而是传入的参数。通过类保存这些参数。
那么在重载__call__方法的时候,需要接受一个函数,返回一个函数。
class logging(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func): # 接受函数
def wrapper(*args, **kwargs):
print "[{level}]: enter function {func}()".format(
level=self.level,
func=func.__name__)
func(*args, **kwargs)
return wrapper #返回函数
@logging(level='INFO')
def say(something):
print "say {}!".format(something)
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Python中deque的操作安排11/22
- ♥ python列表生成的两种语法11/26
- ♥ 最全Python数据工具箱:标准库、第三方库和外部工具都在这里了01/03
- ♥ 五分钟了解 Python 中的函数12/04
- ♥ python 使用 get() 访问字典值10/17
- ♥ python生成器如何解析11/07
内容反馈