是否可以使用属性方法有条件地覆盖类属性?
如果我有这个类,我可以通过传入dict来实例化它:
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 :(得分: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 :(得分: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
我相信这个技巧可以看作是模板方法设计模式的应用,即使它应用于属性。