Inherited class variable modification in Python

PythonPython 2.7

Python Problem Overview


I'd like to have a child class modify a class variable that it inherits from its parent.

I would like to do something along the lines of:

class Parent(object):
    foobar = ["hello"]

class Child(Parent):
    # This does not work
    foobar = foobar.extend(["world"])

and ideally have:

Child.foobar = ["hello", "world"]

I could do:

class Child(Parent):
    def __init__(self):
      type(self).foobar.extend(["world"])

but then every time I instantiate an instance of Child, "world" gets appended to the list, which is undesired. I could modify it further to:

class Child(Parent):
    def __init__(self):
      if type(self).foobar.count("world") < 1:
          type(self).foobar.extend(["world"])

but this is still a hack because I must instantiate an instance of Child before it works.

Is there a better way?

Python Solutions


Solution 1 - Python

Assuming you want to have a separate list in the subclass, not modify the parent class's list (which seems pointless since you could just modify it in place, or put the expected values there to begin with):

class Child(Parent):
    foobar = Parent.foobar + ['world']

Note that this works independently of inheritance, which is probably a good thing.

Solution 2 - Python

You should not use mutable values in your class variables. Set such values on the instance instead, using the __init__() instance initializer:

class Parent(object):
    def __init__(self):
        self.foobar = ['Hello']

class Child(Parent):
    def __init__(self):
        super(Child, self).__init__()
        self.foobar.append('world')

Otherwise what happens in that the foobar list is shared among not only the instances, but with the subclasses as well.

In any case, you'll have to avoid modifying mutables of parent classes even if you do desire to share state among instances through a mutable class variable; only assignment to a name would create a new variable:

class Parent(object):
    foobar = ['Hello']

class Child(Parent):
    foobar = Parent.foobar + ['world']

where a new foobar variable is created for the Child class. By using assignment, you've created a new list instance and the Parent.foobar mutable is unaffected.

Do take care with nested mutables in such cases; use the copy module to create deep copies if necessary.

Solution 3 - Python

Passing in an argument to __init__('world') makes it more clear:

class Parent():
    def __init__(self):
        self.foobar = ['Hello']

class Child(Parent):
    def __init__(self, h):
        super().__init__()
        self.foobar.append(h)

g = Child('world')
print(f'g.foobar = {g.foobar}')
p = Child('how are you?')
print(f'p.foobar = {p.foobar}')

Output:

g.foobar = ['Hello', 'world']
p.foobar = ['Hello', 'how are you?']

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDMackView Question on Stackoverflow
Solution 1 - Pythonuser395760View Answer on Stackoverflow
Solution 2 - PythonMartijn PietersView Answer on Stackoverflow
Solution 3 - PythonLeon ChangView Answer on Stackoverflow