type(d) != type(d.copy()) when type(d).issubclass(dict)

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Dec 25 17:41:49 EST 2010


On Sat, 25 Dec 2010 15:58:35 +0000, Duncan Booth wrote:

> kj <no.email at please.post> wrote:
> 
>> Watch this:
>> 
>>>>> class neodict(dict): pass
>> ...
>>>>> d = neodict()
>>>>> type(d)
>><class '__main__.neodict'>
>>>>> type(d.copy())
>><type 'dict'>
>> 
>> 
>> Bug?  Feature?  Genius beyond the grasp of schlubs like me?
> 
> Feature.

I'd say it is neither, and call it a bloody nuisance that nevertheless 
has some justification.


> In (almost?) all cases any objects constructed by a subclass of a
> builtin class will be of the original builtin class. So, for example,
> subclass a string and concatenating your subclassed objects still
> produces a string.

Yes, and the consequence is that any serious subclass must overload every 
method which returns a new instance, otherwise your new subclass doesn't 
"stick" -- you find it being replaced by the builtin as soon as you start 
doing something useful with it.

This is especially a nuisance for subclasses of (say) float, where you 
end up writing heaps of boilerplate like this:

class MyFloat(float):
    def __add__(self, other):
        return self.__class__(super(MyFloat, self).__add__(other))
    # and the same for __mul__, __sub__, __rsub__, __pow__, ... 


> This is reasonable behaviour as for builtin classes performance is more
> important than fully implementing polymorphism. If you want to subclass
> a builtin class you need to be aware of this and override the behaviour
> where it matters.

Yes, but I think builtins could probably afford one extra identity check. 
Something like this:


# Pseudocode
if type(self) is builtin type:
    do exactly what is done now
else:
    do something slower, but kinder for superclasses


For all I know, the slower branch might be something as simple as calling 
the C equivalent of type(self)(arg).



-- 
Steven



More information about the Python-list mailing list