裝飾器 decorator
官方文檔定義
decorator -- 裝飾器 返回值為另一個函數(shù)的函數(shù)航邢,通常使用 @wrapper 語法形式來進行函數(shù)變換施绎。裝飾
器的常見例子包括 classmethod() 和 staticmethod()溯革。
裝飾器語法只是一種語法糖,以下兩個函數(shù)定義在語義上完全等價:
def f(...):
...
f = staticmethod(f)
@staticmethod
def f(...):
...
同的樣概念也適用于類谷醉,但通常較少這樣使用致稀。有關裝飾器的詳情可參見 函數(shù)定義和 類定義的文
檔。
相關知識點
- 函數(shù)俱尼,類都是對象
函數(shù)可以當做參數(shù)傳遞或返回值
- 閉包
內(nèi)部函數(shù)使用外部函數(shù)定義的變量
返回內(nèi)部函數(shù)對象在外邊調(diào)用
參考范例
- 不帶參數(shù)的裝飾器
import time
def showtime(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print('spend is {}'.format(end_time - start_time))
return wrapper
@showtime #foo = showtime(foo)
def foo():
print('foo..')
time.sleep(3)
@showtime #doo = showtime(doo)
def doo():
print('doo..')
time.sleep(2)
foo()
doo()
- 被裝飾的函數(shù)帶參數(shù)
import time
def showtime(func):
def wrapper(a, b):
start_time = time.time()
func(a,b)
end_time = time.time()
print('spend is {}'.format(end_time - start_time))
return wrapper
@showtime #add = showtime(add)
def add(a, b):
print(a+b)
time.sleep(1)
@showtime #sub = showtime(sub)
def sub(a,b):
print(a-b)
time.sleep(1)
add(5,4)
sub(3,2)
- 帶參數(shù)的裝飾器
import time
def time_logger(flag = 0):
def showtime(func):
def wrapper(a, b):
start_time = time.time()
func(a,b)
end_time = time.time()
print('spend is {}'.format(end_time - start_time))
if flag:
print('將此操作保留至日志')
return wrapper
return showtime
@time_logger(2) #得到閉包函數(shù)showtime,add = showtime(add)
def add(a, b):
print(a+b)
time.sleep(1)
add(3,4)
- 定義類裝飾器裝飾函數(shù)
import time
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self):
start_time = time.time()
self._func()
end_time = time.time()
print('spend is {}'.format(end_time - start_time))
@Foo #bar = Foo(bar)
def bar():
print('bar..')
time.sleep(2)
bar()
- 裝飾器裝飾類
# 定義一個裝飾器
def decorator(cls):
print("這里可以寫被裝飾類新增的功能")
return cls
# 定義一個類 A,并使用decorator裝飾器裝飾
@decorator # 裝飾器的本質(zhì) A = decorator(A)抖单,裝飾器返回類本身,還是之前的類遇八,只是在返回之前增加了額外的功能
class A(object):
def __init__(self):
pass
def test(self):
print("test")
描述器 descriptor
官方文檔定義
descriptor -- 描述器 任何定義了 get(), set() 或 delete() 方法的對象矛绘。當一個類屬
性為描述器時,它的特殊綁定行為就會在屬性查找時被觸發(fā)刃永。通常情況下货矮,使用 a.b 來獲取、設置
或刪除一個屬性時會在 a 的類字典中查找名稱為 b 的對象斯够,但如果 b 是一個描述器囚玫,則會調(diào)用對應
的描述器方法喧锦。理解描述器的概念是更深層次理解 Python 的關鍵,因為這是許多重要特性的基礎抓督,
包括函數(shù)裸违、方法、屬性本昏、類方法供汛、靜態(tài)方法以及對超類的引用等等。
有關描述符的方法的詳情可參看 descriptors涌穆。
@property屬性
@property是個描述器 descriptor
參考源碼
class property(object):
"""
Property attribute.
fget
function to be used for getting an attribute value
fset
function to be used for setting an attribute value
fdel
function to be used for del'ing an attribute
doc
docstring
Typical use is to define a managed attribute x:
class C(object):
def getx(self): return self._x
def setx(self, value): self._x = value
def delx(self): del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
Decorators make defining new properties or modifying existing ones easy:
class C(object):
@property
def x(self):
"I am the 'x' property."
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
"""
...
@wrap,update_wrapper
修改被裝飾函數(shù)的元信息
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
'__annotations__')
參考源碼
################################################################################
### update_wrapper() and wraps() decorator
################################################################################
# update_wrapper() and wraps() are tools to help write
# wrapper functions that can handle naive introspection
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
'__annotations__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Update a wrapper function to look like the wrapped function
wrapper is the function to be updated
wrapped is the original function
assigned is a tuple naming the attributes assigned directly
from the wrapped function to the wrapper function (defaults to
functools.WRAPPER_ASSIGNMENTS)
updated is a tuple naming the attributes of the wrapper that
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)
"""
for attr in assigned:
try:
value = getattr(wrapped, attr)
except AttributeError:
pass
else:
setattr(wrapper, attr, value)
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
# Issue #17482: set __wrapped__ last so we don't inadvertently copy it
# from the wrapped function when updating __dict__
wrapper.__wrapped__ = wrapped
# Return the wrapper so this can be used as a decorator via partial()
return wrapper
def wraps(wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Decorator factory to apply update_wrapper() to a wrapper function
Returns a decorator that invokes update_wrapper() with the decorated
function as the wrapper argument and the arguments to wraps() as the
remaining arguments. Default arguments are as for update_wrapper().
This is a convenience function to simplify applying partial() to
update_wrapper().
"""
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
參考資源鏈接
python3 裝飾器全解
Python 使用裝飾器裝飾類
Python@property詳解及底層實現(xiàn)介紹