0

I want to use the super function to write a string into a list of a specific instance of a parent object. Here's my code so far:

#!/usr/bin/env python
# test.py

class Master(object):
    def __init__(self):
        pass

class Sub1(Master):
    list = []
    def __init__(self):
        pass

class Sub2(Sub1):
    def __init__(self, name):
        super(Sub2, self).list.append(name)

m = Master()
m.foo = Sub1()
m.foo.bar = Sub2('something')

m.bla = Sub1()
m.bla.blub = Sub2('else')

print(m.foo.list)

In this case the output is of course

['something', 'else']

However I want it to be just 'something'.

How can I achieve this?

I tried:

class Sub1(Master):
    def __init__(self):
        self.list = []

Which yields:

AttributeError: 'super' object has no attribute 'list'

Is there an easy solution?

martineau
  • 119,623
  • 25
  • 170
  • 301
boseki
  • 13
  • 2
  • I don't think you should be using inheritance here. Maybe pass a `parent` argument to `__init__`? – internet_user Apr 09 '18 at 13:19
  • You have to call the `Sub1` constructor from your `Sub2` `__init__` method. – Aran-Fey Apr 09 '18 at 13:21
  • Possible duplicate of [Python class inheritance: AttributeError: '\[SubClass\]' object has no attribute 'xxx'](https://stackoverflow.com/questions/10268603/python-class-inheritance-attributeerror-subclass-object-has-no-attribute) – Aran-Fey Apr 09 '18 at 13:21
  • Are you sure you really need inheritance here ? Inheritance is a `is-a` relationship, not a "contains" relationship. – bruno desthuilliers Apr 09 '18 at 13:31
  • No, i'm not really sure i need inheritance.... In this case it looks like `Master` contains `Sub1` which contains `Sub2`, but later i actually want to inherit certain parameters and methods. In the real life it's something like Animals --> Mammals --> Dogs. – boseki Apr 09 '18 at 13:38

2 Answers2

0

As you have noted, if you define lst as a class attribute in Sub1, it is shared among all instances, which is not what you want. So you have to define lst as an instance attribute in Sub1 but then it has to be managed by an instance of Sub1 and not an instance of Sub2. Here is a modified code that offers what you expect:

class Master(object):
    def __init__(self):
        super().__init__()

class Sub1(Master):
    def __init__(self):
        super().__init__()
        self.lst = []
    def add(self, item):
        self.lst.append(item.name)

class Sub2(Sub1):
    def __init__(self, name):
        super().__init__()
        self.name = name

m = Master()
m.foo = Sub1()
m.foo.add(Sub2('something'))

m.bla = Sub1()
m.bla.add(Sub2('else'))

print(m.foo.lst)
print(m.bla.lst)

Here is the ouput:

['something'] <-- m.foo.lst
['else'] <-- m.bla.lst

Rem1: When using super() the whole class hierarchy has to be collaborative (i.e. use super() in the constructor).

Rem2: In Python3, super() is equivalent to super(classname, self)

Rem3: Don't use list as a variable name (it is a builtin type)

Rem4: My code stores only the name attribute in the list to mimic the example your gave, but I guess that in real life you would rather store instances of Sub2 in that list. To do so, simply remove the .name in the addfunction.


EDIT : Thinking a bit more about my answer, I came to another solution that may be closer to your initial attempt. Let me know which one works best for your actual problem...

class Master(object):
    def __init__(self):
        super().__init__()

class Sub1(Master):
    def __init__(self):
        super().__init__()
        self.lst = []

class Sub2(Sub1):
    def __init__(self, parent, name):
        super().__init__()
        parent.lst.append(name)

m = Master()
m.foo = Sub1()
m.foo.bar = Sub2(m.foo, 'something')

m.bla = Sub1()
m.bla.blub = Sub2(m.bla, 'else')

print(m.foo.lst)
print(m.bla.lst)
sciroccorics
  • 2,357
  • 1
  • 8
  • 21
-1

Your actual problem seems to be in the way you initialize list.

You need to assign it in __init__(), not within the class body, to avoid it being shared between all instances of the class (see Static class variables in Python).

class Sub1(Master):
    def __init__(self):
        self.list = []
AKX
  • 152,115
  • 15
  • 115
  • 172