modifying __new__ of list subclass

Steven Bethard steven.bethard at gmail.com
Tue Aug 15 12:30:56 EDT 2006


Ken Schutte wrote:
> Steven Bethard wrote:
>>
>> The __new__ method is for immutable types.  So things like str and int 
>> do their initialization in __new__.  But for regular mutable types, 
>> you should do your initialization in __init__::
> 
> I see... So, is there a use for __new__ in mutable types?   From my 
> list-derirved class, it was obviously being called, but it's return 
> value is totally ignored?

Not ignored, it's just having it's __init__ method called after your 
__new__ method.

It might help for a moment to consider what happens when you call a 
class object, e.g.::

     c = C()

Just like any other object, when Python sees the ``()``, it looks for a 
__call__ method on the object.  Now classes are instances of the 
``type`` type, which has a call method that looks something like::

     def __call__(cls, *args, **kwargs):
         result = cls.__new__(cls, *args, **kwargs)
         if isinstance(result, cls):
             result.__init__(*args, **kwargs)
         return result

What's happening in your list case is that list.__init__ clears the list::

     >>> l = [1, 2, 3]
     >>> l.__init__()
     >>> l
     []

So even though your __new__ method returns the object you want, the 
__init__ method is clearing out all the items you've added and then 
re-adding them as it normally would. To prove this to yourself, take a 
look at what happens when we override __init__::

     >>> class mylist(list):
     ...     def __new__(cls, items):
     ...         result = super(mylist, cls).__new__(cls)
     ...         for item in items:
     ...             result.append('%s_' % item)
     ...         return result
     ...
     >>> mylist([1, 2, 3])
     [1, 2, 3]
     >>> class mylist(list):
     ...     def __new__(cls, items):
     ...         result = super(mylist, cls).__new__(cls)
     ...         for item in items:
     ...             result.append('%s_' % item)
     ...         return result
     ...     def __init__(self, items):
     ...         pass
     ...
     >>> mylist([1, 2, 3])
     ['1_', '2_', '3_']

Of course, I've made __new__ work above, but the simpler solution is 
just to override __init__ since that's where all the work's being done 
anyway.

See Alex Martelli's response to answer your question "So, is there a use 
for __new__ in mutable types?".  You'd probably only want to override 
__new__ if you were going to use the class as a factory to produce a 
bunch of different types of objects.

STeVe



More information about the Python-list mailing list