2013-10-18 106 views
2

我在與裝飾的第一個經驗,我創建了一個裝飾類,用於過濾目標函數的結果,在默認情況下會返回一個特定的順序:參數傳遞給裝飾器時調用裝飾功能

class Filter(object): 
    def __init__(self, id=None): 
     self.id = id 

    def __call__(self, func): 
     def wrapper(*args): 
      entity_ids = func(*args) 
      result = {} 
      for k, v in entity_ids.items(): 
       if self.id: 
        if '_' + str(self.id) in k: 
         result.update({k: v}) 
      return result 
     return wrapper 

我用的裝飾在一些其他類的方法是這樣的:

class SomeClass(object): 
    @Filter(id=None) 
    def get_ids(*args): 
     return result_sequence 

我如何定義的論據,裝飾調用類方法時:

>>>sc = SomeClass() 
>>>sc.get_ids(*args) # I want to pass the id kwarg for Filter here 

在此先感謝

回答

2

馬丁的回答是詳盡的...或者差不多。如果你想調用的函數裝飾你可以使用關鍵字ARG做到這一點,即當要能夠覆蓋「ID」的說法:

class Filter(object): 
    def __init__(self, id=None): 
     self.id = id 

    def __call__(self, func): 
     def wrapper(*args, **kwargs): 
      id = kwargs.get("id", self.id) 
      entity_ids = func(*args) 
      result = {} 
      for k, v in entity_ids.items(): 
       if id: 
        if '_' + str(id) in k: 
         result.update({k: v}) 
      return result 
     return wrapper 

但請注意,這意味着 1.你將不得不通過'id'作爲關鍵字參數,如果你想過載默認的 2.你WONT能夠通過kargs裝飾功能的方式(但你不會傳遞kargs)

作爲一個附註(和這裏稍微有點OT但是......),你的包裝功能的實現可能會有所改進:

 def wrapper(*args, **kwargs): 
      id = kwargs.get("id", self.id) 
      if not id: 
       # no need to go further 
       return {} 

      id = "_%s" % id 
      entity_ids = func(*args) 
      result = dict(
       (k, v) for k, v in entity_ids.items() 
       if id in k 
       ) 
      return result 
3

您在應用類定義的Filter裝飾;它是您在id參數傳遞:

@Filter(id=None) 

如果id應該是別的東西,你需要通過在那裏的價值。

Filter()對象在@Filter(id=None)線創建的,則調用。您也可以將代碼重寫爲:

class SomeClass(object): 
    def get_ids(*args): 
     return result_sequence 
    get_ids = Filter(id=None)(get_ids) 

因爲這是Python在處理裝飾器時所做的。

這是Filter.__call__()方法,取代get_ids,可以不再指定參數,以當時的Filter()對象的返回值SomeClass.get_ids()現在是您的裝飾器返回的嵌套wrapper()函數。

如果要在調用裝飾方法時指定id,則需要更改wrapper()簽名以接受(可選)額外的id參數。因爲你已經支持*args,你唯一的選擇就是增加一個**kwargs包羅萬象的論據來支持可選關鍵字參數:

def wrapper(*args, **kwargs): 
    id = kwargs.get('id', self.id) 
    entity_ids = func(*args) 
    result = {} 
    for k, v in entity_ids.items(): 
     if id: 
      if '_' + str(id) in k: 
       result.update({k: v}) 
    return result 

在這裏,而不是直接使用self.id,一個id關鍵字參數在包裝件覆蓋id值設置在裝飾類:

sc.get_ids(*args, id='foo') 

您可能想要將任何關鍵字參數傳遞給包裝函數;在這種情況下,我會使用:

def wrapper(*args, **kwargs): 
    id = kwargs.pop('id', self.id) 
    entity_ids = func(*args, **kwargs) 
    result = {} 
    for k, v in entity_ids.items(): 
     if id: 
      if '_' + str(id) in k: 
       result.update({k: v}) 
    return result 

這裏,id關鍵字參數是傳遞剩餘的關鍵字參數被包裝的函數之前刪除

0

你不得不改變你的包裝:

class Filter(object): 
    def __init__(self, id=None): 
     self.id = id 

    def __call__(self, func): 
     def wrapper(*args, **kwargs): 
      id = kwargs.get('id', self.id) 
      entity_ids = func(*args) 
      result = {} 
      for k, v in entity_ids.items(): 
       if self.id: 
        if '_' + str(self.id) in k: 
         result.update({k: v}) 
      return result 
     return wrapper 

這給你一個機會,在調用包裝方法的時候給一個替代id值:

class SomeClass(object): 
    @Filter(id=None) 
    def get_ids(*args): 
     return result_sequence 

Filter對象__call__方法現在返回一個包含額外的id kwarg的包裝。因此,您可以覆蓋在類定義時給出的id值:

sc = SomeClass() 
sc.get_ids(*args, id='other') # I want to pass the id kwarg for Filter here 
+1

def wrapper(* args,id = None):引發SyntaxError:無效語法 –

+0

@FrancescoDellaVedova Thx,已更正。 – glglgl