Why IterableUserDict?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Sep 18 05:12:15 CEST 2010

I was writing some tests for a mapping class I have made, and I decided 
to run those same tests over dict and UserDict. The built-in dict passed 
all the tests, but UserDict failed one:

class SimpleMappingTest(unittest.TestCase):
    type2test = UserDict.UserDict
    def test_iter(self):
        k, v = [0, 1, 2, 3], 'abcd'
        m = self.type2test(zip(k, v))
        it = iter(m)
        self.assert_(iter(it) is it)
        self.assertEquals(sorted(it), k)  # This line fails.
    # many more tests

To cut a long story short, the problem is that UserDict doesn't support 
the modern iteration protocol. Python falls back on the old-fashioned 
__getitem__ iteration protocol, but since it expects IndexError rather 
than KeyError, iteration fails for UserDict once it hits key=4.

If I look at the source code for the UserDict module, I discover that 
there's a second mapping class, IterableUserDict, specifically to make 
UserDict iterable. To do this requires a single one-line method:

class IterableUserDict(UserDict):
    def __iter__(self):
        return iter(self.data)

This class was apparently added to the module in 2.2 -- it doesn't exist 
in 2.1.

Now that boggles my brain. Why was support for iteration added as a 
subclass, instead of simply adding the __iter__ method to UserDict? 
UserDict is supposed to be a drop-in replacement for dict (although the 
use-cases for it are much fewer now that we can inherit from dict), so it 
doesn't make sense to me to have a non-iterable UserDict plus a subclass 
which is iterable.

Can anyone shed any light on this apparently bizarre design decision?


More information about the Python-list mailing list