decorator
前提:everything in python is object even function,attributes,variables,params
看这篇之前请先看closure:python简单进阶,closure
两个有趣的例子
def inc(x):
return x + 1
def dec(x):
return x - 1
# 传进一个方法,和一个参数
# 返回这个方法
def operation(func, x):
return func(x)
print(operation(inc, 1))
执行结果
2
# 可以看作 closure,只不过保存的参数是方法
# 其实就是closure,只不过保存的参数是方法
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
pretty = make_pretty(ordinary)
pretty()
print(pretty.__closure__[0].cell_contents)
执行结果
I got decorated
I am ordinary
<function ordinary at 0x000000001BD854A8>
另外一种写法
add the @make_pretty to ordinary() is same to ordinary = make_pretty(ordinary)
def smart_divide(func):
def inner(a, b):
print("I am going to divide ", a, "and", b)
if (b == 0):
print("Whoops! cannot divide")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
return a / b
print(divide(1, 2))
print(divide(1, 0))
看上面的形式可以总结出,能够给别的函数作为修饰器用的必须有如下的特性
- 作为修饰器的函数内部必须有一个
inner()
函数,且最终要返回inner
- 作为修饰器的函数内部
inner()
函数的参数个数必须和被修饰的函数接收的参数数目一直 - 修饰器函数必须接受一个参数,这个参数就是被修饰的方法
遵守如上写法,我们就能写一个修饰器
写一个能修饰任何方法的修饰器
def walk_for_all(func):
def inner(*args, **kwargs):
print "包装"
print func(*args, **kwargs)
print "包装"
return inner
修饰器可以多个同时修饰
def father_protect(func):
def inner(*args, **kwargs):
print("F" * 30)
func(*args, **kwargs)
print("F" * 30)
return inner
def mother_protect(func):
def inner(*args, **kwargs):
print("M" * 30)
func(*args, **kwargs)
print("M" * 30)
return inner
@father_protect
@mother_protect
def child(msg):
print(msg)
child("I am save")
执行结果
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
I am save
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
上面的例子都是我仔细写的,如果认真看完的话,应该会对decorator有比较好的理解。
带参数和不带参数的区别
CLASS_DICT = {}
# 带参数, 实际上就相当于执行了一遍函数, 返回的是修饰器本身
def class_decorator(_type):
def _real_decorator(_class):
def __call(*args, **kwargs):
return _class(*args, **kwargs)
CLASS_DICT[_type] = A
return __call
return _real_decorator
# 不带参数, 就是第一层拿到的是class, 第二层拿到的是执行时传进来的参数
# 和函数的修饰器一样的, 第一层就是函数本身, 第二层是执行时传进来的参数
def class_decorator_2(_class):
def __call(*args, **kwargs):
return _class(*args, **kwargs)
return __call
# @class_decorator('A')
@class_decorator_2
class A(object):
def __init__(self):
self.a = 1
a = A()
print a.a
核心:
带参数时相当于执行了一遍函数, 返回的是修饰器
修饰器的参数, 第一层是类 | 函数本身, 第二层是call() 时传进来的参数, 类就是实例化时的参数, 函数就是执行时的参数