Python: How can I inherit from the built-in list type?
Solution 1
The list
type usually does the actual initialisation of the list inside its __init__()
method, as it is the convention for mutable types. You only need to overwrite __new__()
when subtyping immutable types. While you can overwrite __new__()
when subclassing list, there is not much point in doing so for your use case. It's easier to just overwrite __init__()
:
class MyList(list):
def __init__(self, *args):
list.__init__(self, *args)
self.append('FirstMen')
self.name = 'Westeros'
Also note that I recommend against using super()
in this case. You want to call list.__init__()
here, and not possibly anything else.
Solution 2
First of all, are you doing this as an exercise to understand __new__
? If not, there is almost certainly a better way to do what you're trying to do. Could you explain what you'd like to achieve here?
That said, here's what's happening in your example:
- You invoke
MyList([1,2,3,4])
- This first invokes
MyList.__new__(MyList,[1,2,3,4])
- Your implementation calls
list.__new__(MyList,[1,2,3,4])
This returns a new instance ofMyList
, with no elements.list.__new__
does not populate the list. It leaves that tolist.__init__
, which is never called. - Your
__new__
method appends'FirstMen'
to the emptyMyList
instance. - Your
__new__
method returns the instance ofMyList
. -
MyList.__init__([1,2,3,4])
is invoked. - It sets the
name
attribute to'Westeros'
. - It returns.
- The instance is assigned to
my_list
and printed.
See here for an explanation of __new__
: http://docs.python.org/reference/datamodel.html#basic-customization
Comments
-
pjhades almost 2 years
I want to add some attributes to the built-in
list
type, so I wrote this:class MyList(list): def __new__(cls, *args, **kwargs): obj = super(MyList, cls).__new__(cls, *args, **kwargs) obj.append('FirstMen') return obj def __init__(self, *args, **kwargs): self.name = 'Westeros' def king(self): print 'IronThrone' if __name__ == '__main__': my_list = MyList([1, 2, 3, 4]) print my_list
but
my_list
contains only the element'FirstMen'
. Why my__new__
doesn't work here? And how should I inherit from a built-in type likelist
? Is it the same for the immutable types likestr
? -
pjhades over 12 yearsAh, I forgot to call the superclass's
__init__
. But how about the immutable types? Or is there a general rule about when__new__
should be overridden? -
Sven Marnach over 12 years@PJ.Hades: Only overwrite it if you need to. This is generally the case if you need to influence the construction of the immutable data. Subclassing
tuple
to add further methods and attributes does not require to overwrite__new__()
. If in doubt, just read the documentation. -
pjhades over 12 yearsI knew the cause of this problem. Thanks for your explanation :)
-
Sven Marnach over 12 yearsNote that if
MyList.__init__()
did calllist.__init__()
, it would replace the content of the list by[1, 2, 3, 4]
, so the'FirstMen'
would be gone. -
Istiaque Ahmed over 6 years@SvenMarnach,
self.append('FirstMen')
- where doesFirstMen
append - tolist
orMyList
? -
ucb over 3 yearsWhy would you use
list.__init__()
oversuper().__init__()
? -
Sven Marnach over 3 years@ucb Generally, constructors of subclasses don't have necessarily the same prototype as the base class.
super()
may call the constructor of a random other class in a multiple inheritence scenario, which only works well when the constructors collaborate. It may not matter much, but I personally think usingsuper()
here just adds some unnecessary confusion. You know exactly what constructor you want to call, so it's best to be explicit about it.