1、装饰器详解
1)理解闭包
要想了解装饰器,首先要了解一个闭包的概念,闭包是在函数中再嵌套一个函数,并且引用外部函数的变量,例如,def outer(x):
def inner(y):
return x + y
return inner
print(outer(8)(5))
输出结果:
13
如代码所示,在outer函数内,又定义了一个inner函数,并且inner函数又引用了外部函数outer的变量x,如此就是一个闭包。在执行输出时,outer(8)(5),第一个括号传进去的值返回inner函数,其实就是返回8 + y,所以再传第二个参数进去,就可以得到返回值8 + 5。
2)装饰器
其实装饰器就是一个闭包,装饰器是闭包的一种应用。python装饰器就是用于拓展原来函数功能的一种函数,不同之处是它的返回值也是一个函数,使用python装饰器的好处是在不更改原函数方法的代码就可以给函数方法增加新的功能。def debug(func):
def wrapper():
print("[DEBUG]: enter {}()".format(func.__name__))
return func()
return wrapper
@debug
def hello():
print("hello")
hello()
上面示例使用装饰器不修改函数的情况下,很简单的增加了日志的输出。
3)带参数的日志输出
装饰器是可以增加参数,例如,def logging(level):
def outwrapper(func):
def wrapper(*args, **kwargs):
print("[{0}]: enter {1}()".format(level, func.__name__))
return func(*args, **kwargs)
return wrapper
return outwrapper
@logging(level="INFO")
def hello(a, b, c):
print(a, b, c)
hello("c","java","python")
4) 类装饰器
类的装饰器用法与函数装饰器没有太大区别,实质是使用了类的方法中call方法来实现类的直接调用。class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[DEBUG]: enter {}()".format(self.func.__name__))
return self.func(*args, **kwargs)
@logging
def hello(a, b, c):
print(a, b, c)
hello("c","java","python")
类装饰器也可以带参数,例如,class logging(object):
def __init__(self, level):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print("[{0}]: enter {1}()".format(self.level, func.__name__))
return func(*args, **kwargs)
return wrapper
@logging(level="TEST")
def hello(a, b, c):
print(a, b, c)
hello("c","java","python")
2、使用装饰器实现类中两个同名方法调用
类中两个同名的方法通过version装饰器指定不同的参数,实现两个方法的分别调用:
version_store = {}
def version(v):
def dec(f):
name = f.__qualname__
version_store[(name, v)] = f
def method(self, *args, **kwargs):
f = version_store[(name, self.version)]
return f(self, *args, **kwargs)
return method
return dec
class Product(object):
def __init__(self, version):
self.version = version
@version("1.0")
def function(self):
print("1.0")
@version("2.0")
def function(self):
print("2.0")
Product("1.0").function()
Product("2.0").function()