python装饰器,简单来说就是一个返回函数的函数或者实现了__call__函数的返回函数的类装饰器。和闭包函数很像,每个都是一个独立的实例
通过@符号来扩展函数能力
https://www.cnblogs.com/mark-zh/p/11384546.html
如果装饰器不带参数:
def my_decorator(func):
def inner_func(*args,**kwargs):
print('in inner func')
return func(*args,**kwargs)
return inner_func
@my_decorator
def my_func(string):
print(string)
my_func('nihao') # 等价于my_decorator(my_func)('nihao')
# output:
in inner func
nihao
如果装饰器带参数:
def my_decorator(dec_var):
def dec(func):
def inner_func(*args,**kwargs):
print('in inner func')
print(dec_var)
return func(*args,**kwargs)
return inner_func
return dec
@my_decorator('dec_var=hello')
def my_func(string):
print(string)
my_func('nihao') #等价于 my_decorator('dec_var=hello')(my_func)('nihao')
#output
in inner func
dec_var=hello
nihao
如果是装饰器类,不带参数的话,需要满足:
基于类装饰器的实现,必须实现__call__和__init__两个内置函数。
init:接收被装饰函数
call:实现装饰逻辑
class logger(object):
def __init__(self,func):
self._func=func
def __call__(self,*args,**kwargs):
print('in logger class')
return self._func(*args,**kwargs)
@logger
def my_func(string):
print(string)
my_func('nihao')
#output
in logger class
nihao
如果是装饰器类,带参数的话,需要满足:
基于类装饰器的实现,必须实现__call__和__init__两个内置函数。
init:不再接收被装饰函数,而是接收传入的参数
call:接收被装饰的函数,实现装饰逻辑
class logger(object):
def __init__(self,level):
self.level=level
def __call__(self,func,*args,**kwargs):
def my_decorator(*args,**kwargs):
print('in logger class')
func(*args,**kwargs)
return my_decorator
@logger
def my_func(string):
print(string)
#output
in logger class
nihao
被类装饰之后,还可以直接访问类的方法,像继承一样,__call__就像是为类扩展了新的函数能力(my_func),然后通过my_func又可以访问别的类成员,又反过来扩展了my_func的能力,其实可以这么理解,被类装饰的函数,他需要先生成类的实例,所以自然而然这个被装饰的函数就成为了一个入口来访问类的方法和成员:
class Deco(object):
local_val='helloworld'
def __init__(self,func):
self._func=func
def __call__(self,*args,**kwargs):
print('in Deco class')
return self._func(*args,**kwargs)
def local_func(self):
print('it is local func')
@Deco
def my_func(val):
print(val)
my_func('nihao')
my_func.local_func()
print(my_func.local_val)
#output
in Deco class
nihao
it is local func
helloworld
总之就是包几层的问题而已,使用装饰器后,函数的__name__属性会成为return的函数名,例如my_func.__name__会变成my_decorator,可以使用functools.wraps这个装饰器来获取原函数信息:
