2012-10-08 32 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