[英]How to conditionally override a Python class property with a method
Is it possible to conditionally override a class property with a property method? 是否可以使用属性方法有条件地覆盖类属性?
If I have this class which I can instantiate by passing in a dict: 如果我有这个类,可以通过传递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"
And I make this instance and set bar
to ''
or None
: 然后我创建此实例并将bar
设置为''
或None
:
my_foo = Foo(**{'bar':u''})
and then I call the bar
property: 然后调用bar
属性:
my_foo.bar
and get 并得到
u"I have overridden foo's bar"
I would like to have the property method bar
returned, instead of the bar
value that was passed in when the object was created. 我想返回属性方法bar
,而不是创建对象时传递的bar
值。
Can I do that somehow? 我能以某种方式做到吗? Any help would be awesome. 任何帮助都是极好的。
Python properties can't be overwritten, as doing so raises an AttributeError
. Python属性不能被覆盖,因为这样做会引发AttributeError
。 However, you could try storing your override values and then looking them up when the property is executed: 但是,您可以尝试存储您的替代值,然后在执行属性时查找它们:
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
To override a property you have to act on the class and not on the instance, because their machinery, on the instance, gets called before __dict__
lookup and you end up with AttributeError
s. 要覆盖属性,您必须在类上而不是实例上起作用,因为在实例上调用__dict__
之前,将调用它们的机制,最后得到AttributeError
。 Instead you can set a different property on the class. 相反,您可以在类上设置其他属性。
But to do so you either have to modify your class every time you create an instance(which I bet you do not want), or you have to generate new classes dynamically. 但是要这样做,您要么在每次创建实例时都要修改类(我敢打赌您不希望这样做),要么必须动态生成新类。
For example: 例如:
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)
And the results are: 结果是:
>>> d = SubType(3) #property changed
>>> d.val
4
>>> f = SubType(2) #same property as super class
>>> f.val
2
I don't like much this kind of hacks. 我不太喜欢这种骇客。 Probably the easier way of doing thing is calling a private method that computes the property value, for example: 也许做事的更简单方法是调用一个计算属性值的私有方法,例如:
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
Which yields the same results as before: 产生与以前相同的结果:
>>> d = SubFoo(3)
>>> d.val
4
>>> f = SubFoo(2)
>>> f.val
2
I believe this trick could be seen as an application of the Template Method design pattern, even though it is applied to properties. 我相信,即使将技巧应用于属性,也可以将其视为模板方法设计模式的一种应用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.