原文链接:https://www.zhihu.com/question/26930016/answer/1047233982
1、定义:装饰器,顾名思义,就是增强函数或类的功能的一个函数。
举例:现计算 add 函数的执行时间
import time
def add(a,b):
start_time=time.time()
res=a+b
exec_time=time.time()-start_time
return res
然后又计算sub函数的执行时间,如果不使用装饰器
import time
def add(a,b):
start_time=time.time()
res=a-b
exec_time=time.time()-start_time
return res
如果使用装饰器,就可以减少sub函数前后的重复代码
import tima
# 定义装饰器
def time_calc(func):
def wrapper(*args,**kargs):
start_time=time.time()
f=func(*args,**kargs) # 执行“原函数”,并得到函数执行结果
exec_time=time.time()-start_time
return f # 返回原函数的执行结果到return wrapper
return wrapper # 返回收到的结果到“原函数”
# 函数传入time_calc的参数后,先不执行wrapper函数,而是先return wrapper,
# 即开始执行wrapper函数,同时“原函数”的参数a、b传入*args,**kargs
# 使用装饰器
@time_calc
def add(a,b):
return a+b
@time_calc:
return a-b
2、作用:增强函数的功能,确切的说,可以装饰函数,也可以装饰类。
3、原理:函数是python的一等公民,函数也是对象。
4、使用装饰器
1)装饰器自身不传入参数(采用两层函数定义装饰器)
def login(func):
def wrapper(*args,**kargs):
print('函数名:%s'%func.__name__)
return func(*args,**kargs)
return wrapper
@login
def f():
print('函数本身:inside decorator!')
f()
# 输出
# 函数名:f
# 函数本身:inside decorator!
2)装饰器自身传入参数(采用三层函数定义装饰器)
def login(text):
def decorator(func):
def wrapper(*args,**kargs):
print('%s---%s'%(text,func.__name__))
return func(*args,**kargs)
return wrapper
return decorator
# 一层一层往里执行,最后再一层一层往外返回
@login('this is a parameter of decorator')
def f():
print('2020-07-24')
f()
# 输出
# this is a parameter of decorator---f
# 2020-07-24
5、内置装饰器
常见的内置装饰器:
1)@property:把类内方法当成属性来使用,必须要有返回值,相当于getter;
2)@staticmethod:静态方法。与普通方法类似,参数里面不用self,若此方法和类相关,但又不需要类和实例中的任何信息、属性等,就可以选择静态方法。比如我们检查是否开启了日志功能,这个和类相关,但是跟类的属性和实例都没有关系。
# -*- coding:utf-8 -*-
log_enabled = True
class A:
class_attr = "attr"
def __init__(self):
pass
@staticmethod
def static_foo():
if log_enabled:
print("log is enabled")
else:
print("log is disabled")
A.static_foo()
3)@classmethod:类方法。当我们只需和类直接进行交互,而不需要和实例进行交互时,类方法是最好的选择。类方法与实例方法类似,但是传递的不是类的实例,而是类本身,第一个参数是cls。我们可以用类的实例调用类方法,也可以直接用类名来调用。
# -*- coding:utf-8 -*-
class A:
class_attr = "attr"
def __init__(self):
pass
@classmethod
def class_foo(cls):
print("running class_foo(%s)" % (cls.class_attr))
a = A()
a.class_foo()
A.class_foo()