Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > type(d) != type(d.copy()) when type(d).issubclass(dict)

Reply
Thread Tools

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

 
 
kj
Guest
Posts: n/a
 
      12-24-2010



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?

~kj

 
Reply With Quote
 
 
 
 
David Robinow
Guest
Posts: n/a
 
      12-24-2010
On Fri, Dec 24, 2010 at 1:52 PM, kj <> 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?

copy, here, is a dict method. It will create a dict.
If you really need it, you could try this:

import copy
class neodict(dict):
def copy(self):
return copy.copy(self)

d = neodict()
print type(d)
dd = d.copy()
print type(dd)
 
Reply With Quote
 
 
 
 
Steven D'Aprano
Guest
Posts: n/a
 
      12-25-2010
On Sat, 25 Dec 2010 15:58:35 +0000, Duncan Booth wrote:

> kj <> 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
 
Reply With Quote
 
John O'Hagan
Guest
Posts: n/a
 
      12-26-2010
On Sat, 25 Dec 2010, Steven D'Aprano wrote:
> On Sat, 25 Dec 2010 15:58:35 +0000, Duncan Booth wrote:
> > kj <> 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__, ...

[...]

I've occasionally wished I could just:

import builtin_subclass_fixer

class MyList(list):
def __init__(self):
builtin_subclass_fixer.fix(self)
...
...

to automatically ensure that new objects returned by MyList methods are of the
same class without my having to identify and override every such method.

IMO one of the benefits of subclassing is that you can just "bolt on"
additional behaviour without having to know all the inner workings of the
superclass, a benefit that is somewhat defeated by this behaviour of builtins.

OTOH - not that I advocate nuisance as a deterrent - the nuisance factor of
this has encouraged me to look harder for simpler solutions. Most of the time
I've realised I didn't really need to subclass at all, and thus avoided "lazy
subclassing".

John
 
Reply With Quote
 
kj
Guest
Posts: n/a
 
      12-26-2010


"John O'Hagan" <> writes:

>IMO one of the benefits of subclassing is that you can just "bolt on"
>additional behaviour without having to know all the inner workings of the
>superclass, a benefit that is somewhat defeated by this behaviour of builtins.


I agree. I've read the old post/articles by GvR and other over
how great it will be now that one can subclass Python builtin types
like any other class (GvR even gives explicit examples of this
luscious possibility in his paper on type/class unification). But
now I'm discovering so many caveats, exceptions, and gotchas about
subclassing builtins that I have to conclude that this much celebrated
new capability is basically useless... Just like "readability
counts", it is also true that "conceptual clarity" counts, and
treating builtins as classes in Python is the most obfuscated design
I've ever seen.

UserDict, come back, all is forgotten!

~kj
 
Reply With Quote
 
kj
Guest
Posts: n/a
 
      12-26-2010
In <Xns9E59A27DEF178duncanbooth@127.0.0.1> Duncan Booth <> writes:

>kj <> 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.


>In (almost?) all cases any objects constructed by a subclass of a builtin
>class will be of the original builtin class.



What I *really* would like to know is: how do *you* know this (and
the same question goes for the other responders who see this behavior
of dict as par for the course). Can you show me where it is in
the documentation? I'd really appreciate it. TIA!

~kj
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off




Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57