views:

50

answers:

4

Hi,

just encountered a problem at dict "type" subclassing. I did override __iter__ method and expected it will affect other methods like iterkeys, keys etc. because I believed they call __iter__ method to get values but it seems they are implemented independently and I have to override all of them.

Is this a bug or intention they don't make use of other methods and retrieves values separately ?

I didn't find in the standard Python documentation description of calls dependency between methods of standard classes. It would be handy for sublassing work and for orientation what methods is required to override for proper behaviour. Is there some supplemental documentation about python base types/classes internals ?

+2  A: 

If not specified in the documentation, it is implementation specific. Implementations other that CPython might re-use the iter method to implement iterkeys and others. I would not consider this to be a bug, but simply a bit of freedom for the implementors.

I suspect there is a performance factor in implementing the methods independently, especially as dictionaries are so widely used in Python.

So basically, you should implement them.

André Caron
Yep, I did supposed it's the way to implement them all. Can anybody else can confirm it's not a bug or a feature removed in Pyton 3.x
David Unric
+5  A: 

Subclass Mapping or MuteableMapping from the collections module instead of dict and you get all those methods for free.

Here is a example of a minimal mapping and some of the methods you get for free:

import collections
class MinimalMapping(collections.Mapping):
    def __init__(self, *items ):
        self.elements = dict(items)
    def __getitem__(self, key):
        return self.elements[key]
    def __len__(self):
        return len(self.elements)
    def __iter__(self):
        return iter(self.elements)

t = MinimalMapping()
print (t.iteritems, t.keys, t.itervalues, t.get)

To subclass any of the builtin containers you should always use the appropriate baseclass from the collections module.

THC4k
+1 because this is the right thing to do!
jathanism
Thx for the hint. I did mentioned dict as an example. I'm looking for a more general principles of subclassing in Python.
David Unric
@David Unric: This *is* the general principle.. `dict` etc are meant to be as fast as possible, not to be easily extendable - that's what the base classes in the collections module are for.
THC4k
@THC4k: Speed might be one reason to subclass `dict` instead of `collections.Mapping`. Needless to say I disagree with the your statement about **always** subclassing from `collections` baseclass rather than builtins. One of the reasons for the introduction of the new object model in Python 2.2 was precisely so you *could* subclcass the builtins.
martineau
+1 for mind reading: although this does not answer the written question at all, the poster chose it as the answer!
André Caron
+1  A: 

You know the saying: "You know what happens when you assume." :-)

They don't officially document that stuff because they may decide to change it in the future. Any unofficial documentation you may find would simply document the current behavior of one Python implementation, and relying on it would result in your code being very, very fragile.

When there is official documentation of special methods, it tends to describe behavior of the interpreter with respect to your own classes, such as using __len__() when __nonzero__() isn't implemented, or only needing __lt()__ for sorting.

Since Python uses duck typing, you usually don't actually need to inherit from a built-in class to make your own class act like one. So you might reconsider whether subclassing dict is really what you want to do. You might choose a different class, such as something from the collections module, or to encapsulate rather than inheriting. (The UserString class uses encapsulation, since you can't subclass strings.) Or just start from scratch.

kindall
A: 

Instead of subclassing dict, you could instead just create make your own class that has exactly the properties you want without too much trouble. Here's a blog post with an example of how to do this. The __str__() method in it isn't the greatest, but that's easily corrected the rest provide the functionality you seek.

martineau