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:
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
:
my_foo = Foo(**{'bar':u''})
and then I call the bar
property:
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.
Can I do that somehow? Any help would be awesome.
Python properties can't be overwritten, as doing so raises an 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. 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.