Python中的装饰器
2017-12-29 本文已影响37人
fisher爱吃鱼
Python中的装饰器
不带参数的装饰器
#!coding:utf-8
def use_logging(func):
def wrapper(*args, **kwargs):
print("%s is running" % func.__name__)
return func(*args)
return wrapper
@use_logging
def foo():
print("i am foo")
@use_logging
def bar():
print("i am bar")
foo()
bar()
带参数的装饰器
#!coding:utf-8
def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
print("[%s]%s is running" % (level, func.__name__))
return func(*args)
return wrapper
return decorator
@use_logging(level='error')
def foo():
print("i am foo")
@use_logging(level='warn')
def bar():
print("i am bar")
foo()
bar()
类装饰器
#!coding:utf-8
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self):
print('class decorator runing')
self._func()
print('class decorator ending')
@Foo
def bar():
print('bar')
bar()
functools.wraps
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的 docstring
、__name__
、参数列表,先看例子:
#!coding:utf-8
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
print(f.__name__) # prints 'with_logging'
print(f.__doc__) # prints None
函数 f
等价于:
def f(x):
"""does some math"""
return x + x * x
f = logged(f)
不难发现,函数 f
被 with_logging
取代了,当然它的 docstring
,__name__
就是变成了with_logging
函数的信息了。
这个问题就比较严重的,好在我们有 functools.wraps
,wraps
本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。
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'
内置装饰器
@staticmathod
、@classmethod
、@property
装饰器的顺序
@a
@b
@c
def f ():
等效于
f = a(b(c(f)))