最近总体研究了一下python的装饰器,在这里做一下总结
普通装饰器
普通装饰器基本如下,使用起来简单方便,下面这个是最简单的例子,调用方法前打印一下方法的名字
def decorator(func):
def wrapper():
print func.__name__
func()
return wrapper
@decorator
def func():
do something
稍微解释一下,func这个函数在被编译器编译之后会变成这样,因此调用的时候实际上是掉用的wrapper这个函数了
func = decorator(func)
带参数函数的装饰器
上面提到的普通装饰器,装饰的是没有参数的函数,下面这个展示的是如果写一个带有参数的函数的装饰器,其实也很简单
def decorator(func):
def wrapper(*args, **kwargs):
print func.__name__
func(*args, **kwars)
return wrapper
@decorator
def func(something):
print something
装饰器本身带参数
装饰器本身带参数个人认为是很常见的用法,可以对装饰器本身做一些控制,从代码看跟无参数装饰器最直观的区别就是要多包一层
def decorator(arg):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print args
print func.__name__
func(*args, **kwargs)
return inner_wrapper
return wrapper
@decorator(arg=arg)
def func(something):
print something
类作为装饰器
类作为装饰器这个平时用的不多,这个用法还是很神奇的,主要是要用到__call__方法
class Decorator(object): # python3 中就不需要显式的继承object了
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print self.func.__name__
func(*args, **kwargs)
@Decorator
def func(something):
print something
跟普通装饰器其实是一样的,调用Decorator装饰的方法func相当于是
Decorator(func).__call__()
类作为带参数的装饰器
有了上面这几个装饰器做基础,这个理解起来也不难
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, func):
def wrapper(*args, **kwargs):
print func.__name__
func(*args, **kwargs)
return wrapper
@Decorator(arg=arg)
def func(something):
print something
使用装饰器的一些坑
1. 错误的函数签名和文档
装饰器装饰过的函数看上去名字没变,其实已经变了,包括doc。使用标准库里的functools.warps基本可以解决这个问题
def decorator(func):
@warps(func)
def warpper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
2. 不能用来装饰@classmethod 和 @staticmethod
因为@staticmethon和@classmethod返回的并不是一个callable对象,而是一个staticmethod的对象,这不符合装饰器的定义。解决方案是把装饰器放在@classmethod和@staticmethod之前。注意这里说的之前不是写在前一行,而是后一行,因为装饰器是从离函数最近的这个开始起作用的
@classmethod
@decorator
def func():
do_something