3

I'm learning Python and I've found something about how Python constructs a sub class which confuses me.

I have a class that inherits from the list class as follows.

class foo(list):
    def __init__(self, a_bar):
        list.__init__([])
        self.bar = a_bar

I know that list.__init__([]) needs to be there but I'm confused about it. It seems to me that this line will just create a new list object and then assign it to nothing, so I would suspect that it would just get garbage collected. How does Python know that this list is part of my object? I suspect that there is something happening behind the scenes and I'd like to know what it is.

lowteq
  • 111
  • 1
  • 2
  • 5

4 Answers4

3

The multiple-inheritance-safe way of doing it is:

class foo(list):
    def __init__(self, a_bar):
        super(foo, self).__init__()
        ...

which, perhaps, makes it clearer that you're calling the baseclass ctor.

thebjorn
  • 26,297
  • 11
  • 96
  • 138
  • It needs a bit more than that to be MI-safe. –  Jul 28 '12 at 18:29
  • 3
    Such as all classes in the inheritance tree agreeing on `__init__` arguments using `super`. See [Python's super() considered super!](http://rhettinger.wordpress.com/2011/05/26/super-considered-super/). –  Jul 28 '12 at 18:52
2

You usually do this when subclassing and overriding the __init__() function:

list.__init__(self)

If you're using Python 3, you can make use of super():

super().__init__()
Blender
  • 289,723
  • 53
  • 439
  • 496
1

The actual object is not created with __init__ but with __new__. __init__ is not for creating the object itself but for initializing it --- that is, adding attributes, etc. By the time __init__ is called, __new__ has already been called, so in your example the list was already created before your code even runs. __init__ shouldn't return anything because it's supposed to initialize the object "in-place" (by mutating it), so it works by side-effects. (See a previous question and the documentation.)

Community
  • 1
  • 1
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
1

You're partly right:

list.__init__([]) 

"creates a new list object." But this code is wrong. The correct code _should_be:

list.__init__(self)

The reason you need it to be there is because you're inheriting from a list that has it's own __init__() method where it (presumably) does important to initialize itself. When you define your own __init__() method, you're effectively overriding the inherited method of the same name. In order to make sure that the parent class's __init__() code is executed as well, you need to call that parent class's __init__().

There are several ways of doing this:

#explicitly calling the __init__() of a specific class
#"list"--in this case
list.__init__(self, *args, **kwargs)     

#a little more flexible. If you change the parent class, this doesn't need to change
super(foo, self).__init__(*args, **kwargs) 

For more on super() see this question, for guidance on the pitfalls of super, see this article.

Community
  • 1
  • 1
Joel Cornett
  • 24,192
  • 9
  • 66
  • 88