文章目錄
- Decorators基礎
- Decorators調用規律
- Decorators典型應用 – singleton class
Python中的Decorators表面看起來很像C#的Attribute,其實不然,Python的Decorators和C#的Attribute完全是兩個東西。Python的Decorators讓我想到了設計模式中的裝飾者模式(Decorator Pattern)。
Decorator Pattern
Attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending functionnality.
Python中的通過Decorators對函數、方法或類進行裝飾,從而達到增加對象的職責,或控制對象調用的作用。而C#的Attribute僅僅是起到中繼資料標識作用,最終通過反射擷取這些特定資訊。
先來個簡單的樣本,先定義一個Coffee類,
class Coffee(object):
def get_cost(self):
return 1.0
coffee = Coffee()
print coffee.get_cost() # 1.0
這時,我想通過裝飾者模式計算Milk的價格,通常這樣實現:
class Milk(Coffee):
def __init__(self, coffee):
self.coffee = coffee
def get_cost(self):
return self.coffee.get_cost() + 0.5
coffee = Coffee()
coffee = Milk(coffee)
print coffee.get_cost() # 1.5
上面是經典的裝飾者模式的實現,Python中通過Decorators可以實現成這樣:
def milk_decorator(get_cost):
def get_milk_cost(self):
return get_cost(self) + 0.5
return get_milk_cost
class Coffee(object):
@milk_decorator
def get_cost(self):
return 1.0
coffee = Coffee()
print coffee.get_cost() #1.5
假設一下,如果有更多的,比如:Whip, Sprinkles, Tee, 必須為每個裝飾者都實現一個函數,將會出現函數爆炸,我們可以只實現一個通用的Decorator函數,通過在get_cost函數添加多個@Decorator,這很符合Decorator Pattern的思想。
def get_cost_decorator(additional_cost):
def wrapper1(func):
def wrapper2(instance):
return func(instance) + additional_cost
return wrapper2
return wrapper1
class Coffee(object):
@get_cost_decorator(0.5)
@get_cost_decorator(0.7)
@get_cost_decorator(0.2)
def get_cost(self):
return 1.0
coffee = Coffee()
print coffee.get_cost() #2.4
上面的get_cost_decorator類看上去比較複雜,不要緊,一會再回頭看這個函數。
Decorators基礎
閑話不多說,先看下面的簡單例子:
def myDecorator(func):
def newFunction():
print "inside newFunction"
func()
return newFunction
@myDecorator
def aFunction():
print "inside aFunction()"
aFunction()
最終輸出:
inside newFunction
inside aFunction()
我們看到,myDecorator函數的參數其實是aFunction的函數地址,並且返回一個函數地址,返回的函數才是最終真正調用的地址。最終的調用,等價於:
aFunction = myDecorator(aFunction)
aFunction()
其中,myDecorator也可以使用class來實現,比如:
class myDecorator(object):
def __init__(self, func):
self.func = func
def __call__(self):
print "inside myDecorator"
self.func()
@myDecorator
def aFunction():
print "inside aFunction()"
最終,
aFunction()
相對於
aFunction = myDecorator(aFunction)
aFunction() # __call__
Decorators調用規律
上面的例子,我們可以很容易的得到這樣一個規律:
@A
def f ():
…
最終等價於:
f = A(f)
如果更複雜一些:
@A
@B
@C
def f ():
…
則相對於:
f = A(B(C(f)))
再看看有參數的例子,
@A(args)
def f ():
…
這時,f相當於:
_deco = A(args)
f = _deco(f)
因此,A的實現也會相對複雜一些:
def A(args):
def wrapper1(f):
def wrapper2():
print “before call f()”
f()
return wrapper2
return wrapper1
有點繞吧,嗯,還算簡單,我們回頭看最開頭那個例子,
@get_cost_decorator(0.5)
@get_cost_decorator(0.7)
@get_cost_decorator(0.2)
def get_cost(self):
return 1.0
相當於:
get_cost = get_cost_decorator(0.5)(get_cost_decorator(0.7)(get_cost_decorator(0.2)(get_cost))) # 繞暈了~~
Decorators典型應用 – singleton classdef singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
參考文章:
Decorators for Functions and Methods
Introduction to Python Decorators
Decorator pattern
[Python學習]decorator的使用 - limodou
Python 天天美味系列(總)
Python 天天美味(30) - python資料結構與演算法之快速排序
Python 天天美味(31) - python資料結構與演算法之插入排序
Python 天天美味(32) - python資料結構與演算法之堆排序
Python 天天美味(33) - 五分鐘理解元類(Metaclasses)[轉]
Python 天天美味(34) - Decorators詳解