Question: Inheritance from a buil-in type

Duncan Booth duncan at NOSPAMrcp.co.uk
Tue Sep 30 04:46:15 EDT 2003


afriere at yahoo.co.uk (Asun Friere) wrote in
news:38ec68a6.0309300022.3c8e3304 at posting.google.com: 

> Duncan Booth <duncan at NOSPAMrcp.co.uk> wrote in message
> news:<Xns9405A01F17467duncanrcpcouk at 127.0.0.1>... 
> 
>> 
>> There are two rules. Generally, immutable objects get their initial
>> values from the constructor (__new__) while mutable objects are
>> constructed with a default value (e.g. empty list or dict) and are
>> then set by the initialiser (__init__) method. A few types which you
>> might expect to be immutable are actually mutable (e.g. property).
>>
> 
> What is the thinking behind that? I mean you /can/ pass initial values
> to a mutable using __new__,  eg
> 
>      class MyList (list) :
>          def __new__(cls, *args, **kwargs) :
>              return list.__new__(cls, *args, **kwargs)
> 
> or __init__ to pass values to a newly created immutable, eg
> 
>      class MyTuple (tuple) :
>          def __init__(self, *args, **kwargs) :
>              return super(tuple, self).__init__(*args, **kwargs)
> 
> can't you?  What's the pitfall?
> 
The pitfall is that these aren't doing what you think. In both cases you 
just passed the original arguments straight through, so the list also got 
the arguments it expected in its __init__ method, and the tuple got its 
expected arguments in __new__. If you modify the arguments in any way 
you'll find that your code still only sees the original arguments.

list.__init__ and tuple.__new__ act on their arguments.
list.__new__ and tuple.__init__ ignore their arguments.

Take the tuple example. tuple() takes 0 or 1 arguments, so you can't write:

    tuple(1, 2, 3)

So define a class to do this:

>>> class MyTuple(tuple):
	def __new__(cls, *args):
		return tuple.__new__(cls, args)

	
>>> MyTuple(1, 2, 3)
(1, 2, 3)

Now try this with __init__ and the default __new__ will complain:

>>> class MyTuple(tuple):
	def __init__(self, *args):
		tuple.__init__(self, args)

		
>>> MyTuple(1, 2, 3)
Traceback (most recent call last):
  File "<pyshell#73>", line 1, in ?
    MyTuple(1, 2, 3)
TypeError: tuple() takes at most 1 argument (3 given)


If you try subclassing list, then this example shows clearly that the 
arguments to __new__ are actually ignored:

>>> class MyList (list) :
        def __new__(cls, *args, **kwargs) :
             return list.__new__(cls, *args, **kwargs)
        def __init__(self, *args, **kwargs):
		print "list before init",self
		list.__init__(self, *args, **kwargs)

		
>>> print MyList([1, 2, 3])
list before init []
[1, 2, 3]

 
-- 
Duncan Booth                                             duncan at rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?




More information about the Python-list mailing list