Python properties and inheritance

I have a base class with a property that (get method) I want to rewrite in a subclass. My first thought was something like this:

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 a lambda expression that works:

 age = property(lambda self: self._get_age()) 

So, is this the right solution to use properties and overwrite them in a subclass, or are there other preferred ways to do this?

+57
python inheritance polymorphism properties
Oct 26 '08 at 2:49
source share
9 answers

I just prefer to repeat property() , and also repeat @classmethod decoder when overriding a class method.

Although 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 the properties of Python 2.6, a couple of setter and deleter methods have grown that can be used to apply common properties to a shortcut that is already read-only:

 class C(object): @property def x(self): return self._x @x.setter def x(self, value): self._x = value 
+65
Oct 26 '08 at 10:50
source share

I do not agree that the selected answer is an ideal way to override property methods. If you expect getters and setters to be overridden, then you can use a lambda to provide access to yourself 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, using the property as a decorator, rather than directly calling the property (), I'd love to hear that!

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)) 

Thus, overriding can be easily done:

 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 found this on a geek in a game .

+16
Jan 16 '13 at 0:55
source share

Another way to do this without creating additional classes. I added the set method to show what you are doing 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 far-fetched example, but you should get this idea.

+11
Nov 14 '08 at 22:52
source share

Yes, this is the way to do it; a property declaration is executed during the execution of the definition of the parent class, which means that it can only "see" versions of methods that exist in the parent class. Therefore, when you override one or more of these methods in a child class, you need to re-declare the property using the version (s) of the child class method.

+7
Oct 26 '08 at 3:07
source share

I agree with your decision, which seems to be an on-the-fly method. This article is dedicated to your problem and provides exactly your solution.

+2
Oct. 26 '08 at 3:01
source share

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 
+2
Oct 26 '08 at 3:17
source share

Same as @ mr-b , but with a 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) 

Thus, overriding can be easily done:

 class Bar(Foo): def _get_meow(self): return super(Bar, self)._get_meow() + ', altered by a Bar' 
+2
May 20 '16 at 9:11
source share

I am having trouble setting a property in a parent class from a child class. The following workround extends the parent property, but does this by directly invoking the parent's _set_age method. Wrinkles should always be correct. It's a bit 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) 
0
Jun 02 '15 at 15:52
source share
 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, only mention that the 2.13.4 style guide uses the template method and property

0
Aug 23 '19 at 3:51
source share



All Articles