2012-10-08 50 views
1

是否可以使用屬性方法條件覆蓋類屬性?如何有條件地用方法覆蓋Python類屬性

如果我有這個類,我可以通過傳遞一個字典實例:

def Foo(Object): 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

    # pseudo code (this doesn't work) 
    if not self.bar: 
     @property 
     def bar(self): 
      return u"I have overridden foo's bar" 

我做這種情況下,並設置bar''None

my_foo = Foo(**{'bar':u''}) 

,然後我打電話bar財產:

my_foo.bar 

,並得到

u"I have overridden foo's bar" 

我想有財產法bar返回而不是這是創建對象時傳入的bar值。

我能以某種方式做到嗎?任何幫助都是極好的。

+0

你是什麼意思「有屬性方法返回」?你是說你想'my_foo.bar'返回你傳入的空字符串,但是如果你做了'other_foo = Foo(** {'bar':None})'',那麼你希望'other_foo.bar'運行財產? – BrenBarn

+0

您能否請張貼一些示例代碼和預期結果來說明您的問題?根本不清楚你要求什麼。 – nneonneo

+0

我試圖澄清一些。 – MFB

回答

0

覆蓋您必須作用於類,而不是對實例的屬性,因爲他們的機器,在實例,在__dict__查找之前被調用,並且最終以AttributeError s結束。相反,你可以在課堂上設置不同的屬性。

但要做到這一點,您必須在每次創建實例時修改您的類(我敢打賭,您不需要),或者您必須動態生成新類。

例如:

class Foo(object): 
    def __init__(self, val): 
     self._val = val 
    @property 
    def val(self): 
     return self._val 

class SubType(Foo): 
    def __new__(cls, val): 
     if val % 2: 
      #random condition to change the property 
      subtype = type('SubFoo', (SubType,), 
          {'val': property((lambda self: self._val + 1))}) 
       return object.__new__(subtype) 
      else: 
       return object.__new__(cls) 

而且結果是:

>>> d = SubType(3) #property changed 
>>> d.val 
4 
>>> f = SubType(2) #same property as super class 
>>> f.val 
2 

我不太喜歡這樣的黑客。也許這樣做事情的更簡單的方法是調用,計算屬性值的私有方法,例如:

class Foo(object): 
    def __init__(self, val): 
     self._val = val 
    def _compute_val(self): 
     return self._val 
    @property 
    def val(self): 
     return self._compute_val() 

class SubFoo(Foo): 
    def _compute_val(self): 
     if self._val % 2: 
       return self._val + 1 
     else: 
       return self._val 

其產生相同的結果之前:

>>> d = SubFoo(3) 
>>> d.val 
4 
>>> f = SubFoo(2) 
>>> f.val 
2 

我相信這一招可以看出作爲模板方法設計模式的應用程序,即使它應用於屬性。

+1

謝謝,我需要回家並重新思考我的生活。 – MFB

0

Python屬性不能被覆蓋,因爲這樣做會產生AttributeError。然而,在執行財產時,你可以嘗試保存您的覆蓋值,然後找起來:

def overridable(of): 
    def nf(self): 
     if hasattr(self, "_overrides") and of.__name__ in self._overrides: 
      return self._overrides[of.__name__] 
     return of(self) 
    return nf 


class Foo(object): 
    _overrides = {} 

    def __init__(self, **kwargs): 
     for k, v in kwargs.iteritems(): 
      try: 
       setattr(self, k, v) 
      except AttributeError: 
       self._overrides[k] = v 

    @property 
    @overridable 
    def bar(self): 
     return u'I have overridden foo\'s bar' 


my_foo = Foo(bar=3) 
print my_foo.bar 
+1

eugh ...這是一個瘋狂的黑客... – nneonneo

+0

只是使它與修飾器稍微好:)沒有更多的'進口檢查' –

+0

「作爲做會引發'AttributeError'」 - 這不是全部的故事,它看起來像OP已經注意到,設置'self .__ dict __ ['bar']'將起作用,因爲不會引發異常。它仍然沒有設置任何有意義的屬性,因爲調用屬性底層方法的機制比查找實例'__dict__'更早觸發。 – lvc