[Python-ideas] __len__() for map()

Steven D'Aprano steve at pearwood.info
Sat Dec 1 11:53:20 EST 2018

On Sat, Dec 01, 2018 at 11:07:53AM -0500, Paul Svensson wrote:

> >Here's a map object I prepared earlier:
> >
> >from itertools import islice
> >mo = map(lambda x: x, "aardvark")
> >list(islice(mo, 3))
> >
> >If I now pass you the map object, mo, what should len(mo) return? Five
> >or eight?
> mo = "aardvark"
> list(islice(mo, 3))
> By what magic would the length change?
> Per the proposal, it can only be eight.
> Of course, that means mo can't, in this case, be an iterator.
> That's what the proposal would change.

I already discussed that: map is not currently a sequence, and just 
giving it a __len__ is not going to make it one.  Making it a sequence, 
or a view of a sequence, is a bigger change, but worth considering, as I 
already said in part of my post you deleted.

However, it is also a backwards incompatible change. In case its not 
obvious from my example above, I'll be explicit:

# current behaviour
mo = map(lambda x: x, "aardvark")
list(islice(mo, 3))  # discard the first three items
assert ''.join(mo) == 'dvark'
=> passes

# future behaviour, with your proposal
mo = map(lambda x: x, "aardvark")
list(islice(mo, 3))  # discard the first three items
assert ''.join(mo) == 'dvark'
=> fails with AssertionError

Given the certainty that this change will break code (I know it will 
break *my* code, as I often rely on map() being an iterator not a 
sequence) it might be better to introduce a new "mapview" type rather 
than change the behaviour of map() itself.

On the other hand, since the fix is simple enough:

mo = iter(mo)

perhaps all we need is a depreciation period of at least one full 
release before changing the behaviour.

Either way, this isn't a simple or obvious change, and will probably 
need a PEP to nut out all the fine details.


More information about the Python-ideas mailing list