I think this is a design decision that kernel developers chose at the time they implemented map . There is no universally defined behavior for map when it is used with multiple iterators, quoting Map (higher order function) :
A card with two or more lists faces a processing problem when the lists have different lengths. In this, different languages ββdiffer; some cause an exception, some stop after the length of the shortest list and ignore additional elements in other lists; some extend the length of the longest list, and for already completed lists, pass some placeholder value to a function that does not specify a value.
So, the Python core developers chose None as a placeholder for shorter iterations, while map was introduced in Python in 1993.
But in the case of itertools.imap it is a short circuit with the shortest iterable, because its design is strongly inspired by languages ββsuch as Standard ML, Haskell and APL. In standard ML and Haskell map , the shortest iterable ends (I'm not sure about APL, though).
Python 3 also removed map(None, ...) (or should we say itertools.imap , Python 3 map is actually almost itertools.imap : Move map() from itertools to builtins ) because it was only present in Python 2 because at the time map added in Python in Python, there was no zip() function.
From Issue2186: map and filter should not support None as the first argument (only in Py3k) :
I agree with Guido that we would never create map(None, ...) if zip() . The main use case is out of date.
To get the result you want, I would suggest using itertools.izip_longest with the sentinel ( object() ) value, and not None by default, None will break things if the iterators themselves contain None :
from itertools import izip_longest def solve(seq): sentinel = object() return [tuple(x for x in item if x is not sentinel) for item in izip_longest(*seq, fillvalue=sentinel)] print solve([[1,2,3,4],[5,6]]) # [(1, 5), (2, 6), (3,), (4,)]