Why IterableUserDict?

Discussion in 'Python' started by Steven D'Aprano, Sep 18, 2010.

  1. 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?



    --
    Steven
     
    Steven D'Aprano, Sep 18, 2010
    #1
    1. Advertising

  2. Steven D'Aprano

    Peter Otten Guest

    Steven D'Aprano wrote:

    > 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?


    I looked it up for you:

    http://svn.python.org/view/python/trunk/Lib/UserDict.py?view=log

    """
    Revision 22248 - (view) (download) (as text) (annotate) - [select for diffs]
    Modified Tue Aug 7 17:40:42 2001 UTC (9 years, 1 month ago) by gvanrossum
    File length: 1913 byte(s)
    Diff to previous 21167
    Remove the __iter__ method from the UserDict class -- it can silently
    break old code (in extreme cases). See SF bug #448153.

    Add a new subclass IterableUserDict that has the __iter__ method.

    Note that for new projects, unless backwards compatibility with
    pre-2.2 Python is required, subclassing 'dictionary' is recommended;
    UserDict might become deprecated.
    """

    The bug report is also interesting:

    http://bugs.python.org/issue448153

    Peter
     
    Peter Otten, Sep 18, 2010
    #2
    1. Advertising

  3. Steven D'Aprano

    Terry Reedy Guest

    On 9/17/2010 11:12 PM, Steven D'Aprano wrote:
    > 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:


    You forgot to specify Python version ;-).
    >
    > class SimpleMappingTest(unittest.TestCase):
    > type2test = UserDict.UserDict


    In 3.x, collections.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.


    Not in 3.x

    import collections
    k, v = [0, 1, 2, 3], 'abcd'
    m = collections.UserDict(zip(k, v))
    it = iter(m)
    assert iter(it) is it
    assert sorted(it) == k

    runs clean.

    > If I look at the source code for the UserDict module, I discover that
    > there's a second mapping class, IterableUserDict,


    Not any more. One of numerous 3.x cleanups made possible by dropping
    obsessive back compatibility, which, as Peter explained, wan the reason
    for the hack.

    --
    Terry Jan Reedy
     
    Terry Reedy, Sep 19, 2010
    #3
  4. On Sat, 18 Sep 2010 09:42:14 +0200, Peter Otten wrote:

    [...]
    >> 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?

    >
    > I looked it up for you:
    >
    > http://svn.python.org/view/python/trunk/Lib/UserDict.py?view=log

    [...]
    > The bug report is also interesting:
    >
    > http://bugs.python.org/issue448153


    Oh my.

    Guido is more forgiving than me. I would have left __iter__ in UserDict
    and treated the bug report as a "will not fix".


    Thanks for that.


    --
    Steven
     
    Steven D'Aprano, Sep 19, 2010
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?VGltOjouLg==?=

    Why, why, why???

    =?Utf-8?B?VGltOjouLg==?=, Jan 27, 2005, in forum: ASP .Net
    Replies:
    6
    Views:
    580
    Juan T. Llibre
    Jan 27, 2005
  2. Horace Nunley

    why why why does function not work

    Horace Nunley, Sep 27, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    471
    =?Utf-8?B?UGV0ZXIgQnJvbWJlcmcgW0MjIE1WUF0=?=
    Sep 27, 2006
  3. Mr. SweatyFinger

    VWD why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    389
    =?Utf-8?B?Q2lhcmFuIE8nJycnRG9ubmVsbA==?=
    Dec 21, 2006
  4. Mr. SweatyFinger

    why why why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    4
    Views:
    922
    Mark Rae
    Dec 21, 2006
  5. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,077
    Smokey Grindel
    Dec 2, 2006
Loading...

Share This Page