任務簡單的介紹是: 在新風格對象模型中,Python操做實際上是在類中查找特殊方法的(經典對象是在實例中進行操做的),如今須要將一些新風格的實例包裝到代理中,,此代理能夠選擇將一些特殊的方法委託給內部的被包裝對象。python
代碼實施爲:緩存
1 class Proxy(object): 2 """全部代理的基類""" 3 def __init__(self, obj): 4 super(Proxy, self).__init__() #少了此補會致使無限遞歸循環 5 self._obj = obj 6 7 def __getattr__(self, attribute): 8 return getattr(self._obj, attribute) 9 10 11 def make_binder(unbound_method): 12 def wrapper(self, *arg, **kwargs): 13 return unbound_method(self._obj, *arg, **kwargs) 14 return wrapper 15 16 17 known_proxy_classes = {} 18 19 20 def proxy(obj, *specials): 21 """工廠函數""" 22 obj_cls = obj.__class__ 23 key = obj_cls, specials 24 cls = known_proxy_classes.get(key) 25 if cls is None: 26 cls = type("%sProxy" % ob_cls.__name, (Proxy,), {}) 27 for name in specials: 28 name = '__%s__' % name 29 unbound_method = getattr(obj_cls, name) 30 setattr(cls, name, make_binder(unbound_method)) 31 """緩存之以供進一步使用 32 known_proxy_classes[key] = cls 33 """實例化並返回須要的代理 34 return cls(obj)
代理(以及自動託管)都得歸功於__getattr__機制,在查詢任何屬性時,(包括方法,python並不區分二者),python都會自動調用__getattr__。app
代碼運行結果以下圖:函數
其實結果很容易理解,就是經過特殊方法代理實現子類方法的代理,例如上面實例,因爲代理了list中的len和iter,那麼能夠實現方法len以及迭代,沒有代理geiitem方法,那麼在利用index時就會報錯。spa
在新風格對象中,python操做並不會在運行的時候查找特殊方法:它們依賴於類對象的「槽」。而這些槽會在對象被建立或者修改的時候更新,所以,對於一個代理對象,若是它要把特殊方法託管給被封裝的對象,它自己必須屬於某個量身定作的類。代理