Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I override a field in a base class with a property in a derived class?

I have a base class that uses a field:

class Base(object):
    def __init__(self, member):
        self.member = member

And a derived class that would like to promote this to a property, and add some behaviour:

class Derived(Base):
    @property
    def member(self):
        return super(Derived, self).member

    @member.setter
    def member(self, value):
        print "intercepting setter"
        super(Derived, self).member = value

However, this doesn't correctly delegate to the base class:

>>> d = Derived(0)
intercepting setter

Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    d = Derived(0)
  File "<pyshell#3>", line 3, in __init__
    self.member = 2
  File "<pyshell#6>", line 9, in member
    super(Derived, self).member = value
AttributeError: 'super' object has no attribute 'member'

How should I be doing this?

like image 955
Eric Avatar asked Oct 04 '22 02:10

Eric


2 Answers

You're trying to access the super's member as if it were a class attribute. Try with:

class Derived(Base):
    @property
    def member(self):
        print "intercepting getter"
        return self._member

    @member.setter
    def member(self, value):
        print "intercepting setter"
        self._member = value
like image 55
Chewie Avatar answered Oct 13 '22 11:10

Chewie


I think that promoting a member to a property is the correct way of doing it. It is like having an int member in the base and changing it to a method in the derived class. Or like having a normal method and changing it to a static or class method in the inheriter. I guess this just breaks the concept.

You have several options to solve the issue.

I. How about introducing a property of a different (similar) name which then relays all access to the inherited original name? This would be very simple, won't break anything inherited from the base class. But it would also not allow intercepting access to the original member (done in the base class or whereever).

II. Replace the inherited member completely. This just means store the value in a different member and create the property totally from scratch. Later then let it access the store of the original:

class Base(object):

    def __init__(self, member):
        self.member = member

    def baseAccess(self):
        return self.member

class Derived(Base):
    @property
    def member(self):
        print "getter",
        return self.memberStore

    @member.setter
    def member(self, value):
        print "setter",
        self.memberStore = value

b = Base(24)
print "Base(24)"
print "b.member", b.member
print "b.baseAccess()", b.baseAccess()
d = Derived(23)
print "Derived(23)"
print "d.member", d.member
print "d.baseAccess()", d.baseAccess()

b.member = 43
print "b.member = 43"
print "b.member", b.member
print "b.baseAccess()", b.baseAccess()
d.member = 42
print "d.member = 42"
print "d.member", d.member
print "d.baseAccess()", d.baseAccess()

This is the output:

Base(24)
b.member 24
b.baseAccess() 24
setter getter Derived(23)
d.member getter 23
d.baseAccess() getter 23
b.member = 43
b.member 43
b.baseAccess() 43
setter d.member = 42
d.member getter 42
d.baseAccess() getter 42

So all the interceptors are properly taken into account.

like image 30
Alfe Avatar answered Oct 13 '22 12:10

Alfe