Python中的裝飾器
不帶參數(shù)的裝飾器
#!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()
帶參數(shù)的裝飾器
#!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
使用裝飾器極大地復(fù)用了代碼撒踪,但是他有一個(gè)缺點(diǎn)就是原函數(shù)的元信息不見了愉豺,比如函數(shù)的 docstring
、__name__
、參數(shù)列表,先看例子:
#!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
函數(shù) f
等價(jià)于:
def f(x):
"""does some math"""
return x + x * x
f = logged(f)
不難發(fā)現(xiàn)箕肃,函數(shù) f
被 with_logging
取代了,當(dāng)然它的 docstring
最盅,__name__
就是變成了with_logging
函數(shù)的信息了突雪。
這個(gè)問題就比較嚴(yán)重的,好在我們有 functools.wraps
涡贱,wraps
本身也是一個(gè)裝飾器咏删,它能把原函數(shù)的元信息拷貝到裝飾器函數(shù)中,這使得裝飾器函數(shù)也有和原函數(shù)一樣的元信息了问词。
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'
內(nèi)置裝飾器
@staticmathod
督函、@classmethod
、@property
裝飾器的順序
@a
@b
@c
def f ():
等效于
f = a(b(c(f)))