I have a base class with a property which (the get method) I want to overwrite in the subclass. My first thought was something like:
class Foo(object):
d
Another way to do it, without having to create any additional classes. I've added a set method to show what you do if you only override one of the two:
class Foo(object):
def _get_age(self):
return 11
def _set_age(self, age):
self._age = age
age = property(_get_age, _set_age)
class Bar(Foo):
def _get_age(self):
return 44
age = property(_get_age, Foo._set_age)
This is a pretty contrived example, but you should get the idea.
I ran into problems setting a property in a parent class from a child class. The following workround extends a property of a parent but does so by calling the _set_age method of the parent directly. Wrinkled should always be correct. It is a little javathonic though.
import threading
class Foo(object):
def __init__(self):
self._age = 0
def _get_age(self):
return self._age
def _set_age(self, age):
self._age = age
age = property(_get_age, _set_age)
class ThreadsafeFoo(Foo):
def __init__(self):
super(ThreadsafeFoo, self).__init__()
self.__lock = threading.Lock()
self.wrinkled = False
def _get_age(self):
with self.__lock:
return super(ThreadsafeFoo, self).age
def _set_age(self, value):
with self.__lock:
self.wrinkled = True if value > 40 else False
super(ThreadsafeFoo, self)._set_age(value)
age = property(_get_age, _set_age)
A possible workaround might look like:
class Foo:
def __init__(self, age):
self.age = age
@property
def age(self):
print('Foo: getting age')
return self._age
@age.setter
def age(self, value):
print('Foo: setting age')
self._age = value
class Bar(Foo):
def __init__(self, age):
self.age = age
@property
def age(self):
return super().age
@age.setter
def age(self, value):
super(Bar, Bar).age.__set__(self, value)
if __name__ == '__main__':
f = Foo(11)
print(f.age)
b = Bar(44)
print(b.age)
It prints
Foo: setting age
Foo: getting age
11
Foo: setting age
Foo: getting age
44
Got the idea from "Python Cookbook" by David Beazley & Brian K. Jones. Using Python 3.5.3 on Debian GNU/Linux 9.11 (stretch)
Same as @mr-b's but with decorator.
class Foo(object):
def _get_meow(self):
return self._meow + ' from a Foo'
def _set_meow(self, value):
self._meow = value
@property
def meow(self):
return self._get_meow()
@meow.setter
def meow(self, value):
self._set_meow(value)
This way, an override can be easily performed:
class Bar(Foo):
def _get_meow(self):
return super(Bar, self)._get_meow() + ', altered by a Bar'
I agree with your solution, which seems an on-the-fly template method. This article deals with your problem and provides exactly your solution.
I simply prefer to repeat the property()
as well as you will repeat the @classmethod
decorator when overriding a class method.
While this seems very verbose, at least for Python standards, you may notice:
1) for read only properties, property
can be used as a decorator:
class Foo(object):
@property
def age(self):
return 11
class Bar(Foo):
@property
def age(self):
return 44
2) in Python 2.6, properties grew a pair of methods setter
and deleter
which can be used to apply to general properties the shortcut already available for read-only ones:
class C(object):
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value