[Python-ideas] Suggested MapView object (Re: __len__() for map())

Greg Ewing greg.ewing at canterbury.ac.nz
Sun Dec 2 08:04:31 EST 2018

Chris Angelico wrote:
> I can't help thinking that it will be extremely surprising to have the
> length remain the same while the items get consumed.

That can be fixed. The following version raises an exception if
you try to find the length after having used it as an iterator.
(I also fixed a bug -- I had screwed up the sequence case, and it
wasn't re-iterating properly.)

class MapView:

     def __init__(self, func, *args):
         self.func = func
         self.args = args
         self.iterator = None

     def __len__(self):
         return min(map(len, self.args))

     def __getitem__(self, i):
         return self.func(*list(map(itemgetter(i), self.args)))

     def __iter__(self):
         return map(self.func, *self.args)

     def __next__(self):
         if not self.iterator:
             self.iterator = iter(self)
         return next(self.iterator)

 >>> a = [1, 2, 3, 4, 5]
 >>> b = [2, 3, 5]
 >>> m = MapView(pow, a, b)
 >>> print(next(m))
 >>> print(len(m))
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/Users/greg/foo/mapview/mapview.py", line 12, in __len__
     raise TypeError("Mapping iterator has no len()")
TypeError: Mapping iterator has no len()

It will still report a length if you use len() *before* starting
to use it as an iterator, but the length it returns is correct at
that point, so I don't think that's a problem.

> Are there any
> other non-pathological examples where len(x) != len(list(x))?

No longer a problem:

 >>> m = MapView(pow, a, b)
 >>> len(m) == len(list(m))


More information about the Python-ideas mailing list