What makes an iterator an iterator?

Peter Otten __peter__ at web.de
Wed Apr 18 06:53:46 EDT 2007


Steven D'Aprano wrote:

> class SortedDict(dict):
>     def __iter__(self):
>         for key in sorted(self.keys()):
>             yield key
> 
> Note that using sorted(self) does not work.

That's because sorted() invokes __iter__() if present. To prevent the
recursion you can explicitly invoke dict.__iter__():

>>> class SortedDict(dict):
...     def __iter__(self):
...             return iter(sorted(super(SortedDict, self).__iter__()))
...
>>> sd = SortedDict(a=1, b=2, c=3)
>>> list(sd)
['a', 'b', 'c']

Note that a list of keys is still built before the first key is yielded,
and, unlike dict, you can modify your SortedDict while iterating over it:

>>> for k in sd:
...     if k == "b": sd["x"] = 42
...
>>> sd
{'a': 1, 'x': 42, 'c': 3, 'b': 2}

whereas:

>>> d = dict(a=1, b=2, c=3)
>>> for k in d:
...     if k == "b": d["x"] = 42
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

By the way, I think it would be worthwile to change super() to allow
e. g. super(SomeClass, self)[...] as an alternate spelling for
super(SomeClass, self).__getitem__(...) etc. With such an enhancement
SortedDict would become

class SortedDict(dict): 
    def __iter__(self):
        # doesn't work in current Python
        iter(sorted(super(SortedDict, self))) 


Peter




More information about the Python-list mailing list