2014-02-22 106 views
4

我正在編寫一個用於編排AWS集羣的小框架,並且存在一些反覆出現的常見層次模式。一種這樣的模式是將一組實例收集到一個更大的對象中,然後將一些方法直接委託給所有實例。因此,而不是複製,一遍又一遍我用下面的方式抽象其粘貼相同的樣板代碼:python中的方法委託

def __getattr__(self, item): 
    if not item in self._allowed_items: 
     raise NonDelegatableItem 

    def delegator(): 
     for instance in self.all_instances: 
      getattr(instance, item)() 

    return delegator 

是否有實現的代表團更好的方法或模式?

+1

這是慣用使用'不in'取而代之的,'item',我會說'method'。 –

回答

7

__getattr__在遍歷整個類hirarchy並且未找到該屬性時調用。因此,最好生成一次該方法並將其存儲在類中。然後找到該方法下次需要更少的時間。

>>> X.a 

Traceback (most recent call last): 
    File "<pyshell#15>", line 1, in <module> 
    X.a 
AttributeError: class X has no attribute 'a' 
>>> x.a 
new delegator 
<function delegator at 0x02937D30> 
>>> x.a 
<bound method X.delegator of <__main__.X instance at 0x028DBC60>> 
>>> X.a 
<unbound method X.delegator> 

在這裏你可以看到你的代碼的適應做到這一點:

class NonDelegatableItem(AttributeError): 
    pass 

class X: 
    def __getattr__(self, method_name): 
     self.check_method_name_is_delegator(method_name) 
     return self.create_delegator(method_name) 

    def check_method_name_is_delegator(self, method_name): 
     if method_name not in self._allowed_items: 
      raise NonDelegatableItem('{} can not be delegated'.format(method_name)) 

    @classmethod 
    def create_delegator(cls, method_name): 
     print 'new delegator' 
     def delegator(self, *args, **kw): 
      self.check_method_name_is_delegator(method_name) 
      for instance in self.all_instances: 
       getattr(instance, method_name)(*args, **kw) 
     setattr(cls, method_name, delegator) 
     return delegator 


x = X() 

x._allowed_items = ['a', 'b'] 
+0

好點。我沒有想到在這個過程中分配方法。 – davidk01

+0

非常有幫助。 – mjd2

+0

不錯的一個。不應該'__getattr__'對'check_method_name_is_delegator'的調用被忽略,所以不能再次查找不可授權的屬性(畢竟,某人可以通過'AttributeError'除外''捕獲'NonDelegatableItem')?第二個調用可以放在'delegator'之外,用一個'除了NonDelegatableItem:def委託(self,* args,** kw):raise NonDelegatableItem(...'所以委託僅被檢查一次。 –