装饰器:
1.用于装饰其他函数
2.增强被装饰函数的功能
装饰器需要接受一个函数对象作为参数,以对其进行增强
def deco(func):
def wrapper():
print "decorate something"
func()
print "decorate finish"
return wrapper
@deco
def test_func():
return "test func"
test_func()
output:
decorate something
test func
decorate finish
test_func()被装饰之后,运行函数test_func(),会运行装饰器这个函数
当你在用某个@decorator来修饰某个函数func时,如下所示:
@decorator
def func():
pass
其解释器会解释成下面这样的语句:
func = decorator(func)
先看一个简单的装饰器如下:
def hello(fn):
def wrapper():
print "hello, %s" % fn.__name__
fn()
print "goodby, %s" % fn.__name__
return wrapper
@hello
def foo():
print "i am foo"
foo()
输出:
hello, foo
i am foo
goodby, foo
对于一个装饰器的定义:
@hello
def foo():
print "i am foo"
实际上可以理解成foo = hello(foo),将被包装的函数(foo)当作参数传入装饰器(hello)中,通过一系列包装后将包装后的函数再返回给被包装的函数(foo),实际上就是返回了一个新函数,只不过是根据原函数改造而来并且名字不变。
def out_func(**kwds):
def real_decorator(fn):
arg = kwds['arg1'] + kwds['arg2']
def wapper():
fn()
return kwds['arg1'] + kwds['arg2'] + arg
return wapper
return real_decorator
@out_func(arg1='11111', arg2='22222')
def hello_world():
print('hello world')
print(hello_world())
分析:我的理解是装饰器有两层,内层wapper用于包装,外层decorator(real_decorator)用于接收被包装的函数(hello_world)作为参数,并将包装后的函数(wapper)返回给外部。此处的例子有三层,外层还有一个out_func函数的用处是给内层传递参数,由于外部多了一层函数所以装饰器函数(real_decorator)将装饰器本身返回给out_func,于是@out_func就相当于装饰器。
functools.wraps
我们在使用 Decorator 的过程中,难免会损失一些原本的功能信息。
def logged(func):
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
def f(x):
"""does some math"""
return x + x * x
f = logged(f)
In [24]: f.__name__
Out[24]: with_logging
由于返回的是包装后的with_logging,所以name等基本信息变成了返回的新函数
而functools.wraps 则可以将原函数对象的指定属性复制给包装函数对象, 默认有 module、name、doc,或者通过参数选择。代码如下:
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
print f.__name__ # prints 'f'
print f.__doc__ # prints 'does some math'
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
print f.__name__ # prints 'f'
print f.__doc__ # prints 'does some math'