type(self) not preserved on some builtin methods when subclassing.

average_expires08dec2001_1w3tq5 at safeadd.net average_expires08dec2001_1w3tq5 at safeadd.net
Mon Oct 8 21:29:07 CEST 2001


The following was categorized as "not-a-bug" on the Python sourceforge site
(468887).  Instead of bugging the developers further, I thought maybe folks
here could help me further understand the rationale of the following
behavior and provide useful alternatives:

************
> Python-2.2a4 
>
> For user-defined types derived from built-in types, it 
> appears that built-in methods which return copies are 
> not preserving the type of self. 
>
> >>> class Test(list): pass 
> >>> t=Test() 
> >>> map(type, [t, t[:], t+t]) 
> [<class '__main__.Test'>, <type 'list'>, <type 'list'>] 
> >>> t += t 
> >>> type(t) 
> <class '__main__.Test'> 
>
> Same with types int, dictionary, etc. 
************
And response:

[tim_one]
> This is deliberate.  If, e.g., you don't override the 
> slicing operator in Test, then t[:] is handled by the base 
> class's slicing operator.  The base class can't know what 
> invariants Test needs to preserve, so does the best it can 
> by constructing a list.  If you want operators that return 
> Test instances instead, you have to supply them.
>
> Note that base-class operators *sometimes* returned 
> instances of subclasses in earlier 2.2 alphas, but 
> unpredictably (depending on internal optimizations).  This 
> was properly reported as a bug, and was fixed for 2.2a4; 
> see bug 460020 for details.
***********

The bug report mentioned (460020) does provide some good discussion, and it
appears that considerable work went into creating this behavior.  

>From what I understand, without this behavior Python would have to require
the subclass' constructor to be able to initialize with the same parameter
list as the base class in order for the base class method to be able to
create a new object of the subtype.

If I remember correctly, this is what C++ requires; that is, a default
constructor which doesn't require any arguments.

In any case, it would seem that if a user wants to extend a built-in class,
he/she will either have to:

1) rewrite (in the subclass) all built-in methods which might return copies, 
2) re-copy the return result of the built-in method back into self's
original type, or 
3) re-assign to the __class__ attribute of the return result (isn't this
deprecated however?).
4) some alternative that hopefully is just escaping me...

Note that if UserList is used as the base class instead of list, things work
as (I) expected.  That is, for methods which return copies, the base class
creates a new object using "result = self.__class__(data)" instead of
hardcoding the copy type ("result = UserList(data)").

Any comments or further alternative ideas to avoid options 1-3?

Thanks,

Mark





More information about the Python-list mailing list