Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A neat way of extending a class attribute in subclasses

Tags:

python

Let's say I have the following class

class Parent(object):
    Options = {
        'option1': 'value1',
        'option2': 'value2'
    }

And a subclass called Child

class Child(Parent):
   Options = Parent.Options.copy()
   Options.update({
        'option2': 'value2',
        'option3': 'value3'
   })

I want to be able to override or add options in the child class. The solution I'm using works. But I'm sure there is a better way of doing it.


EDIT

I don't want to add options as class attributes because I have other class attributes that aren't options and I prefer to keep all options in one place. This is just a simple example, the actual code is more complicated than that.

like image 366
Nadia Alramli Avatar asked May 25 '09 16:05

Nadia Alramli


4 Answers

Semantically equivalent to your code but arguably neater:

class Child(Parent):
   Options = dict(Parent.Options,
      option2='value2',
      option3='value3')

Remember, "life is better without braces", and by calling dict explicitly you can often avoid braces (and extra quotes around keys that are constant identifier-like strings).

See http://docs.python.org/library/stdtypes.html#dict for more details -- the key bit is "If a key is specified both in the positional argument and as a keyword argument, the value associated with the keyword is retained", i.e. keyword args override key-value associations in the positional arg, just like the update method lets you override them).

like image 92
Alex Martelli Avatar answered Nov 19 '22 21:11

Alex Martelli


One way would be to use keyword arguments to dict to specify additional keys:

Parent.options = dict(
    option1='value1',
    option2='value2',
)

Child.options = dict(Parent.options,
    option2='value2a',
    option3='value3',
)

If you want to get fancier, then using the descriptor protocol you can create a proxy object that will encapsulate the lookup. (just walk the owner.__mro__ from the owner attribute to the __get__(self, instance, owner) method). Or even fancier, crossing into the probably-not-a-good-idea territory, metaclasses/class decorators.

like image 34
Ants Aasma Avatar answered Nov 19 '22 21:11

Ants Aasma


After thinking more about it, and thanks to @SpliFF suggestion this is what I came up with:

class Parent(object):
    class Options:
        option1 = 'value1'
        option2 = 'value2'


class Child(Parent):
    class Options(Parent.Options):
        option2 = 'value2'
        option3 = 'value3'

I'm still open to better solutions though.

like image 6
Nadia Alramli Avatar answered Nov 19 '22 21:11

Nadia Alramli


Why not just use class attributes?

class Parent(object):
    option1 = 'value1'
    option2 = 'value2'

class Child(Parent):
    option2 = 'value2'
    option3 = 'value3'
like image 4
Jason Baker Avatar answered Nov 19 '22 20:11

Jason Baker