作用: python装饰器的作用在于让程序在没有任何代码变动的情况下可以额外添加功能,使得程序更加简洁。有了装饰器,就可以抽离出与函数功能本身无关的雷同代码并继续重用
原来python装饰器就是这么回事
现在以下程序两个
def say_hello():
print("hello!")
def say_goodbye():
print("goodbye!")
if __name__ == "__main__":
say_hello() #hello!
say_goodbye()#goodbye!
但是现在要在此基础上增加一些功能:在函数print之前要打印出函数得名字。
方案1:
def say_hello():
print("say_hello function")
print("hello!")
def say_goodbye():
print("say_goodbye function")
print("goodbye!")
if __name__ == "__main__":
say_hello() #hello!
say_goodbye()#goodbye!
这样子的方法,嗯嗯额,太low了
方案2:
def debug():
import inspect
caller_name = inspect.stack() [1][3]
print("{}function".format(caller_name))
def say_hello():
debug()
print("hello!")
def say_goodbye():
debug()
print("goodbye!")
if __name__ == "__main__":
say_hello()
say_goodbye()
方案2中每个函数都要调用一下一下debug(), 有点难受!
怎么办呢?这时候python 装饰器就派上用场了。我们可以这么写
def debug(func):
def wrapper():
print("{} function".format(func.__name__))
return func()
return wrapper #返回包装过的函数
def say_hello():
print("hello!")
def say_goodbye():
print("goodbye!")
sayhello=debug(say_hello)
saygoodbye=debug(say_goodbye)
if __name__ == "__main__":
sayhello()
saygoodbye()
debug就是一个装饰器,对原函数func进行了包装,并且不用修改原函数就可以添加需要的功能,当然,我们有更加优雅的写法
def debug(func):
def wrapper():
print("{} function".format(func.__name__))
return func()
return wrapper #返回包装过的函数
@debug
def say_hello():
print("hello!")
@debug
def say_goodbye():
print("goodbye!")
if __name__ == "__main__":
say_hello()
say_goodbye()
@debug等价于func=debug(func)
被装饰函数带有参数:debug()接受一个需要装饰的函数,wrapper接受该函数的参数
def debug(func):
def wrapper(a):
print("{} function".format(func.__name__))
return func(a)
return wrapper #返回包装过的函数
@debug
def say_hello(a):
print(a)
print("hello!")
@debug
def say_goodbye(a):
print(a)
print("goodbye!")
if __name__ == "__main__":
a=1
say_hello(a)
say_goodbye(a)
输出结果
say_hello function
1
hello!
say_goodbye function
1
goodbye!
带有参数的装饰器:如果我们除了输出logging的内容外,还有输出level内容,怎么办?可以这样写。装饰器接受其参数,wrapper接受被装饰的函数,inner_wrapper()接受被装饰函数的参数。
def logging(level):
def wrapper(func):
def inner_wrapper(a):
print("{level}:{func} function".format(level = level,func=func.__name__))
return func(a)
return inner_wrapper
return wrapper
@logging('info')
def say_hello(a):
print(a)
print("hello!")
@logging('info') #相当于 saygoodbye = logging('info')(say_goodbye)
def say_goodbye(a):
print(a)
print("goodbye!")
if __name__ == "__main__":
a=1
say_hello(a)
say_goodbye(a)
output:
info:say_hello function
1
hello!
info:say_goodbye function
1
goodbye!
基于类实现的装饰器:装饰器需要接收一个callable对象,然后返回一个callable对象,在python中,callable对象一般是函数,但是如果某个对象重载了__call__() 函数,那么那个对象就是callable的。
class Test():
def __call__(self):
print("call me!")
t=Test()
t() #call me!
对于一个用类实现的装饰器,可以用__init__()接受一个函数,用__calll__()返回一个函数
class logging(object):
def __init__(self,func):
self.func=func
def __call__(self,*args,**kwargs):
print("{func} function".format(func=self.func.__name__))
return self.func(*args,**kwargs)
@logging
def say_hello(a):
print(a)
print("hello!")
@logging
def say_goodbye(a):
print(a)
print("goodbye!")
带有参数的类实现的装饰器:在构造函数中接受的不是一个函数,而是一个参数,在__call__()中,接受一个被装饰的函数并返回一个函数。wrapper则接受被装饰函数的参数。
class logging(object):
def __init__(self,level):
self.level=level
def __call__(self,func): #接受函数
def wrapper(*args,**kwargs):
print("{level}:{func} function".format(level=self.level, func=func.__name__))
return func(*args,**kwargs)
return wrapper #返回函数
@logging('info')
def say_hello(a):
print(a)
print("hello!")
@logging('info')
def say_goodbye(a):
print(a)
print("goodbye!")
内置装饰器@property:调用类方法就好像引用类属性一样,但是返回的不是函数,而是类对象。
class Test(object):
def __init__(self,name):
self.name=name
def index(self):
print("hello my name is %s" %self.name)
if __name__ == "__main__":
cls = Test("file")
print(cls.name)
cls.index()
以上的代码可以使用内置装饰器@property,如下
class Test(object):
def __init__(self,name):
self.name=name
@property
def index(self):
print("hello my name is %s" %self.name)
if __name__ == "__main__":
cls = Test("file")
print(cls.name)
cls.index # 相当于cls.index()
内置装饰器@staticmethod: 不用实例化就可以调用类的方法,直接类名.方法或者类名.属性。不需要self和cls参数
class Test(object):
@staticmethod
def index():
print("hello my name is a")
if __name__ == "__main__":
Test().index()
Test.index()
内置装饰器@classmethod: 不用实例化就可以调用类的方法,直接类名.方法或者类名.属性。需要cls参数
class Test(object):
@classmethod
def index(cls):
print("hello my name is a")
if __name__ == "__main__":
Test().index()
Test.index()
本人学渣,如有不恰当的地方,欢迎指出!