[Tutor] FrozenDict

eryksun eryksun at gmail.com
Fri Oct 9 08:14:05 CEST 2015


On 10/8/15, Steven D'Aprano <steve at pearwood.info> wrote:
>
> That's one solution, but it is certainly possible for the class to be
> its own iterator, in which case it needs to follow two rules:
>
> (1) self.__next__() needs to return the next value, or raise
> StopIteration;
>
> (2) self.__iter__() needs to return self;
>
> and of course like all dunder methods __next__ and __iter__ need to be
> defined on the class itself, not on the instance.

Except this is generally a bad way to iterate a reiterable. Without a
separate iterator, there's no simple way to maintain state for
concurrent iterations.

file types are an exception. A file is reiterable (i.e. by seeking
back to 0), but the OS file pointer makes a file naturally an
iterator. Thus getting concurrent iterations of a disk file requires
separate file objects that have separate OS file pointers.

FrozenDict.next is an example of what not to do:

    def next(self):
        try:
            value = self.__kwargs.items()[self.__counter][0]
        except IndexError:
            raise StopIteration
        self.__counter += 1
        return value

In Python 2 this iterates the dict's keys by creating a list of (key,
value) tuples -- every time next() is called. In Python 3, you'd have
to explicitly create the list using list(self.__kwargs.items()). The
design also lacks support for concurrent iterations, and not even
multiple iterations since __counter isn't reset in __iter__.

The simple approach is to have __iter__ return an instance of the
wrapped dict's iterator. There's no reason to reinvent the wheel. Plus
in the non-frozen case, the built-in dict iterators are smart enough
to raise an error when the dict is modified, since it's assumed that
any modification to the hash table invalidates the iteration.


More information about the Tutor mailing list