装饰器
python中一切都是对象
所以函数也是对象,
对象是可以被赋值给变量的,通过变量调用函数
>>> def now():
... print 'hello,world'
...
>>> f = now
>>> f()
hello,world
>>>
函数对象有一个_name_属性,作用是拿到函数的名字:
>>> now.__name__
'now'
>>> f.__name__
'now'
>>>
想要增强now()函数的功能,
函数调用前后自动打印log,但是不修改now()函数的定义
代码在运行期间动态的增加功能的方式称为装饰器
本质上装饰器是一个 返回函数的高阶函数
def log(func):
def wrapper(*args,**kw):
print 'call %s():' %func.__name__
return func(*args,**kw)
return wrapper
上面的代码中的log是装饰器,接受函数作为参数,返回一个函数
python的@语法,装饰器置于函数的定义处
@log
def now()
print 'hello world'
调用now()函数不会调用now函数本身,还会在运行now函数前打印log
>>> def log(func):
... def wrapper(*args, **kw):
... print 'call %s():' % func.__name__
... return func(*args, **kw)
... return wrapper
...
>>> @log
... def now():
... print 'hello,world'
...
>>> now()
call now():#打印log
hello,world
>>>
@log放在now()函数的定义处相当于执行:
now = log(now)
log()返回的函数赋给now,原来的函数存在,但是同名的函数变量指向了新函数
调用now()实际上调用了log()中返回的wrapper()函数
wrapper()函数参数是(*args,**kw),因此wrapper()函数可以接受任意参数的调用
wrapper()函数内,先打印log,在调用原始函数
装饰器函数需要传入参数,自定义log的文本
def log(text):
def decorator(func):
def wrapper(*args,**kw):
print '%s %s():'%(text,func.__name__)
return func(*args,**kw)
return wrapper
return decorator
三层嵌套的装饰器的用法:
@log
def now():
print 'hello world'
>>> def log(text):
... def decorator(func):
... def wrapper(*args, **kw):
... print '%s %s():' % (text, func.__name__)
... return func(*args, **kw)
... return wrapper
... return decorator
...
>>> @log('execute')
... def now():
... print 'hello,world'
...
>>> now()
execute now():
hello,world
>>>
3层嵌套的效果是这样的:
now = log('execute')(now)
1. 首先执行log(‘execute’),返回的是decorator函数
2. 再调用返回的函数,参数是now函数,返回值最终是wrapper函数
3. 经过decorator装饰之后的函数,它们的name已经从原来的’now’变成了’wrapper’:
4. now = wrapper,把原始函数的name等属性复制到wrapper()函数中
5. 不需要编写wrapper.name = func.name这样的代码,Python内置的functools.wraps就是干这个事的
完整的装饰器写法
import functools
def log(func):
@functools.wraps(func)
def wrapper(*argw,**kw):
print 'call %s():'%func.__name__
return fucn(*args,**kw)
return wrapper
import functools
def log('text'):
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print '%s %s():'%(text,func.__name__)
return func(*args,**kw)
return wrapper
return decorator