python properties and inheritance
Question:
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):
def _get_age(self):
return 11
age = property(_get_age)
class Bar(Foo):
def _get_age(self):
return 44
This does not work (subclass bar.age returns 11). I found a solution with an lambda expression which works:
age = property(lambda self: self._get_age())
So is this the right solution for using properties and overwrite them in a subclass, or are there other preferred ways to do this?
Answers:
I agree with your solution, which seems an on-the-fly template method.
This article deals with your problem and provides exactly your solution.
Yes, this is the way to do it; the property declaration executes at the time the parent class’ definition is executed, which means it can only “see” the versions of the methods which exist on the parent class. So when you redefine one or more of those methods on a child class, you need to re-declare the property using the child class’ version of the method(s).
Something like this will work
class HackedProperty(object):
def __init__(self, f):
self.f = f
def __get__(self, inst, owner):
return getattr(inst, self.f.__name__)()
class Foo(object):
def _get_age(self):
return 11
age = HackedProperty(_get_age)
class Bar(Foo):
def _get_age(self):
return 44
print Bar().age
print Foo().age
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
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 don’t agree that the chosen answer is the ideal way to allow for overriding the property methods. If you expect the getters and setters to be overridden, then you can use lambda to provide access to self, with something like lambda self: self.<property func>
.
This works (at least) for Python versions 2.4 to 3.6.
If anyone knows a way to do this with by using property as a decorator instead of as a direct property() call, I’d like to hear it!
Example:
class Foo(object):
def _get_meow(self):
return self._meow + ' from a Foo'
def _set_meow(self, value):
self._meow = value
meow = property(fget=lambda self: self._get_meow(),
fset=lambda 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'
so that:
>>> foo = Foo()
>>> bar = Bar()
>>> foo.meow, bar.meow = "meow", "meow"
>>> foo.meow
"meow from a Foo"
>>> bar.meow
"meow from a Foo, altered by a Bar"
I discovered this on geek at play.
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)
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'
class Foo:
# Template method
@property
def age(self):
return self.dothis()
# Hook method of TM is accessor method of property at here
def dothis(self):
return 11
class Bar(Foo):
def dothis(self):
return 44
Same as Nizam Mohamed, just to mention that style guide 2.13.4 using both template method and property
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)
I think the answer from Vladimir Zolotykh is nearly optimal.
For my unterstanding a slightly better variant might be calling the constructer of the superclass.
Resulting in the following code:
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):
super().__init__(age)
if __name__ == "__main__":
a = Foo(11)
print(a.age)
b = Bar(44)
print(b.age)
With this solution, there is no need to reeimplement the property for the subclass. Just tell the subclass, that it should behave like the superclass by using the constructor.
The upper lines result in the following output
Foo: setting age
Foo: getting age
11
Foo: setting age
Foo: getting age
44
with python3.
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):
def _get_age(self):
return 11
age = property(_get_age)
class Bar(Foo):
def _get_age(self):
return 44
This does not work (subclass bar.age returns 11). I found a solution with an lambda expression which works:
age = property(lambda self: self._get_age())
So is this the right solution for using properties and overwrite them in a subclass, or are there other preferred ways to do this?
I agree with your solution, which seems an on-the-fly template method.
This article deals with your problem and provides exactly your solution.
Yes, this is the way to do it; the property declaration executes at the time the parent class’ definition is executed, which means it can only “see” the versions of the methods which exist on the parent class. So when you redefine one or more of those methods on a child class, you need to re-declare the property using the child class’ version of the method(s).
Something like this will work
class HackedProperty(object):
def __init__(self, f):
self.f = f
def __get__(self, inst, owner):
return getattr(inst, self.f.__name__)()
class Foo(object):
def _get_age(self):
return 11
age = HackedProperty(_get_age)
class Bar(Foo):
def _get_age(self):
return 44
print Bar().age
print Foo().age
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
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 don’t agree that the chosen answer is the ideal way to allow for overriding the property methods. If you expect the getters and setters to be overridden, then you can use lambda to provide access to self, with something like lambda self: self.<property func>
.
This works (at least) for Python versions 2.4 to 3.6.
If anyone knows a way to do this with by using property as a decorator instead of as a direct property() call, I’d like to hear it!
Example:
class Foo(object):
def _get_meow(self):
return self._meow + ' from a Foo'
def _set_meow(self, value):
self._meow = value
meow = property(fget=lambda self: self._get_meow(),
fset=lambda 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'
so that:
>>> foo = Foo()
>>> bar = Bar()
>>> foo.meow, bar.meow = "meow", "meow"
>>> foo.meow
"meow from a Foo"
>>> bar.meow
"meow from a Foo, altered by a Bar"
I discovered this on geek at play.
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)
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'
class Foo:
# Template method
@property
def age(self):
return self.dothis()
# Hook method of TM is accessor method of property at here
def dothis(self):
return 11
class Bar(Foo):
def dothis(self):
return 44
Same as Nizam Mohamed, just to mention that style guide 2.13.4 using both template method and property
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)
I think the answer from Vladimir Zolotykh is nearly optimal.
For my unterstanding a slightly better variant might be calling the constructer of the superclass.
Resulting in the following code:
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):
super().__init__(age)
if __name__ == "__main__":
a = Foo(11)
print(a.age)
b = Bar(44)
print(b.age)
With this solution, there is no need to reeimplement the property for the subclass. Just tell the subclass, that it should behave like the superclass by using the constructor.
The upper lines result in the following output
Foo: setting age
Foo: getting age
11
Foo: setting age
Foo: getting age
44
with python3.