G. Chi
G. Chi

Reputation: 49

Strange issue with Python class inheritance

I'm getting an issue with class inheritance in Python that I can't seem to make sense of. It may just be my inexperience with Python.

I was able to replicate the issue with this example (I'm using Python 3.3.4):

class R(object):
    def __init__(self, x, y, w, h):
        self._R = [x, y, w, h]

    @property
    def x(self):
        return self._R[0]
    @x.setter
    def x(self, value):
        self._R[0] = value
    @property
    def y(self):
        return self._R[1]
    @y.setter
    def y(self, value):
        self._R[1] = value
    @property
    def width(self):
        return self._R[2]
    @width.setter
    def width(self, value):
        self._R[2] = value
    @property
    def height(self):
        return self._R[3]
    @height.setter
    def height(self, value):
        self._R[3] = value


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

class A(Base):
    def __init__(self):
        Base.__init__(self)
        self.rect = R(0, 0, 0, 0)

    @property
    def pos(self):
        return (self.rect.x, self.rect.y)
    @pos.setter
    def pos(self, value):
        (self.rect.x, self.rect.y) = value

class B(A):
    def __init__(self):
        A.__init__(self)
        self.foo = "bar"

o = B()
o.pos = (50, 50)

which produces the following error:

Traceback (most recent call last):
  File "main.py", line 52, in <module>
    o = B()
  File "main.py", line 49, in __init__
    A.__init__(self)
  File "main.py", line 37, in __init__
    Base.__init__(self)
  File "main.py", line 33, in __init__
    self.pos = (0, 0)
  File "main.py", line 45, in pos
    (self.rect.x, self.rect.y) = value
AttributeError: 'B' object has no attribute 'rect'

Upvotes: 1

Views: 54

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121166

You are trying to use the self.pos setter before self.rect is set:

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

class A(Base):
    def __init__(self):
        Base.__init__(self)
        self.rect = R(0, 0, 0, 0)

Because self.pos on A is a property, trying to set self.pos requires self.rect to already be set.

move the Base.__init__(self) call down:

class A(Base):
    def __init__(self):
        self.rect = R(0, 0, 0, 0)
        Base.__init__(self)

Now self.rect is set by the time Base.__init__ tries to assign a value to self.pos.

Upvotes: 3

Joran Beasley
Joran Beasley

Reputation: 113930

i think if you change it to this

class A(Base):
    def __init__(self):
       self.rect = R(0, 0, 0, 0)
       Base.__init__(self)

it will work

the problem is that Base.__init__ sets pos , which is a setter method of B that references self.rect but self.rect is not created until after the init call.

so to resolve the issue, simple ensure that self.rect exists before calling __init__ constructor

Upvotes: 2

Related Questions