mart1n
mart1n

Reputation: 6203

Class attribute inheritance when using properties in Python

I have the following code:

class Desc(object):
    @property
    def color_desc(self):
        return 'Color is ' + self.color

    @property
    def brand_desc(self):
        return 'Brand is ' + self.brand

class Text(Desc):
    def __init__(self):
        self.color = 'blue'
        self.brand = 'volvo'

def main():
    t = Text()
    print t.color_desc

if __name__ == '__main__':
    main()

This correctly works and outputs Color is blue when run. However, if I modify the code slightly so that the property is set to an actual Class attribute, as in:

class Desc(object):
    def __init__(self):
        self._color_desc = color_desc
        self._brand_desc = brand_desc

    @property
    def color_desc(self):
        return self._color_desc

    @color_desc.setter
    def color_desc(self):
        self._color_desc = 'Color is ' + self.color

    @property
    def brand_desc(self):
        return self._brand_desc

    @property
    def brand_desc(self):
        self._brand_desc = 'Brand is ' + self.brand


class Text(Desc):
    def __init__(self):
        self.color = 'blue'
        self.brand = 'volvo'

All of a sudden, it errs out with AttributeError: 'Text' object has no attribute '_color_desc'. How come the Text attributes are inherited correctly in the first place but cannot be accessed in the second one. To me, these two solutions seem to do the same thing.

Upvotes: 0

Views: 118

Answers (3)

jonrsharpe
jonrsharpe

Reputation: 121944

It's not clear why you thought your second snippet would work at all. It has the following obvious issues:

  • Desc.__init__ is using two variables (color_desc and brand_desc) that aren't actually passed to it - are you expecting them to be in the global scope?
  • You have two (different!) getters, one of which returns something, and no setter for brand_desc.
  • The color_desc setter neither takes nor uses any parameter, so what exactly is it supposed to be setting?
  • The subclass Text.__init__ doesn't call or pass anything to the superclass version, or do the job itself.

I think what you intended was something like:

class Desc(object):

    def __init__(self, color_desc, brand_desc):
        self._color_desc = color_desc
        self._brand_desc = brand_desc

    @property
    def color_desc(self):
        return 'Color is ' + self._color_desc

    @color_desc.setter
    def color_desc(self, new_color):
        self._color_desc = new_color

    @property
    def brand_desc(self):
        return 'Brand is ' + self._brand_desc

    @brand_desc.setter
    def brand_desc(self, new_brand):
        self._brand_desc = new_brand    


class Text(Desc):

    def __init__(self):
        super(Text, self).__init__('blue', 'volvo')

Although now it looks like Text should be an instance, not a subclass, of Desc. You could also simplify by not assigning to e.g. color_desc at all, using a read-only property:

class Desc(object):

    def __init__(self, color, brand):
        self.color = color
        self.brand = brand

    @property
    def color_desc(self):
        return 'Color is ' + self.color

    @property
    def brand_desc(self):
        return 'Brand is ' + self.brand


car = Desc('blue', 'volvo')
car.color = 'red'
print car.color_desc  # Color is red

Now you set the instance's .color directly, but .color_desc still gives you the nicely-formatted version.

Upvotes: -1

DevShark
DevShark

Reputation: 9102

You need to call the __init__ of the parent class.

Do something like this:

class Text(Desc):
    def __init__(self):
        self.color = 'blue'
        self.brand = 'volvo'
        super(Text, self).__init__(0,0)

The init function of your Desc class is incorrectly define. Do this:

class Desc(object):
    def __init__(self, color_desc, brand_desc):
        self._color_desc = color_desc
        self._brand_desc = brand_desc

Upvotes: 3

loutre
loutre

Reputation: 894

In your Text class, the __init__ is overriding the Desc.__init__ class, so the _color_desc attributes is not initialized.

Upvotes: 3

Related Questions