This question is similar to this other one, with the difference that the data member in the base class is not wrapped by the descriptor protocol.
In other words, how can I access a member of the base class if I am overriding its name with a property in the derived class?
class Base(object):
def __init__(self):
self.foo = 5
class Derived(Base):
def __init__(self):
Base.__init__(self)
@property
def foo(self):
return 1 + self.foo # doesn't work of course!
@foo.setter
def foo(self, f):
self._foo = f
bar = Base()
print bar.foo
foobar = Derived()
print foobar.foo
Please note that I also need to define a setter because otherwise the assignment of self.foo in the base class doesn't work.
All in all the descriptor protocol doesn't seem to interact well with inheritance...
A base class's private members are never accessible directly from a derived class, but can be accessed through calls to the public and protected members of the base class.
Moreover, Object slicing happens when a derived class object is assigned to a base class object, and additional attributes of a derived class object are sliced off to form the base class object.
when we create a child class object,the base class object is auto initiated so base class reference variable can point to child class object. but not vice versa because a child class reference variable can not point to base class object because no child class object is created.
A derived class can have only one direct base class.
Life is simpler if you use delegation instead of inheritance. This is Python. You aren't obligated to inherit from Base
.
class LooksLikeDerived( object ):
def __init__( self ):
self.base= Base()
@property
def foo(self):
return 1 + self.base.foo # always works
@foo.setter
def foo(self, f):
self.base.foo = f
But what about other methods of Base? You duplicate the names in LooksLikeDerived
and simply.
def someMethodOfBase( self, *args, **kw ):
return self.base.someMethodOfBase( *args **kw )
Yes, it doesn't feel "DRY". However, it prevents a lot of problems when "wrapping" some class in new functionality like you're trying to do.
Defining
def __init__(self):
self.foo = 5
in Base
makes foo
a member (attribute) of the instance, not of the class. The class Base
has no knowledge of foo
, so there is no way to access it by something like a super()
call.
This is not necessary, however. When you instanciate
foobar = Derived()
and the __init__()
method of the base class calls
self.foo = 5
this will not result in the creation / overwriting of the attribute, but instead in Derived
's setter being called, meaning
self.foo.fset(5)
and thus self._foo = 5
. So if you put
return 1 + self._foo
in your getter, you pretty much get what you want. If you need the value that self.foo
is set to in Base
's constructor, just look at _foo
, which was set correctly by the @foo.setter
.
class Foo(object):
def __new__(cls, *args, **kw):
return object.__new__(cls, *args, **kw)
def __init__(self):
self.foo = 5
class Bar(Foo):
def __new__(cls, *args, **kw):
self = object.__new__(cls, *args, **kw)
self.__foo = Foo.__new__(Foo)
return self
def __init__(self):
Foo.__init__(self)
@property
def foo(self):
return 1 + self.__foo.foo
@foo.setter
def foo(self, foo):
self.__foo.foo = foo
bar = Bar()
bar.foo = 10
print bar.foo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With