python properties and inheritance

后端 未结 10 1428
粉色の甜心
粉色の甜心 2020-12-12 18:06

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         


        
相关标签:
10条回答
  • 2020-12-12 18:29

    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.

    0 讨论(0)
  • 2020-12-12 18:37

    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)
    
    0 讨论(0)
  • 2020-12-12 18:38

    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)

    0 讨论(0)
  • 2020-12-12 18:39

    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'
    
    0 讨论(0)
  • 2020-12-12 18:42

    I agree with your solution, which seems an on-the-fly template method. This article deals with your problem and provides exactly your solution.

    0 讨论(0)
  • 2020-12-12 18:46

    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
    
    0 讨论(0)
提交回复
热议问题