Python 3 vs Python 2 map comportamiento

En Python 2, un lenguaje común (antiguo, heredado) es usar el map para unir iteradores de longitud irregular utilizando el map(None,iter,iter,...) formulario map(None,iter,iter,...) así:

 >>> map(None,xrange(5),xrange(10,12)) [(0, 10), (1, 11), (2, None), (3, None), (4, None)] 

En Python 2, se extiende para que el iterador más largo tenga la longitud de la lista devuelta y si uno es más corto que el otro, se rellena con None .

En Python 3, esto es diferente. Primero, no puede usar None como un argumento para la llamada en la posición 1:

 >>> list(map(None, range(5),range(10,12))) Traceback (most recent call last): File "", line 1, in  TypeError: 'NoneType' object is not callable 

Bien, puedo arreglar eso así:

 >>> def f(*x): return x ... >>> list(map(f, *(range(5),range(10,12)))) [(0, 10), (1, 11)] 

Pero ahora tengo un problema diferente: el map devuelve la longitud del iterador más corto , ya no se rellena con None .

Como transfiero el código Python 2 a Python 3, este no es un lenguaje raro y terrible, y no he descubierto una solución fácil de instalar.

Desafortunadamente, las herramientas 2to3 no recogen esto, sugiriendo inútilmente:

 -map(None,xrange(5),xrange(10,18)) +list(map(None,list(range(5)),list(range(10,18)))) 

Sugerencias?


Editar

Hay una discusión sobre qué tan común es este idioma. Ver esta publicación tan

Estoy actualizando el código legado escrito cuando aún estaba en la escuela secundaria. Mire los tutoriales de Python de 2003 escritos y discutidos por Raymond Hettinger con este comportamiento específico del mapa que se señala …

itertools.zip_longest hace lo que quieres, con un nombre más comprensible. 🙂

Voy a responder mi propia pregunta esta vez.

Con Python 3x, puedes usar itertools.zip_longest así:

 >>> list(map(lambda *a: a,*zip(*itertools.zip_longest(range(5),range(10,17))))) [(0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (None, 15), (None, 16)] 

También puedes rodar tu propia, supongo:

 >>> def oldMapNone(*ells): ... '''replace for map(None, ....), invalid in 3.0 :-( ''' ... lgst = max([len(e) for e in ells]) ... return list(zip(* [list(e) + [None] * (lgst - len(e)) for e in ells])) ... >>> oldMapNone(range(5),range(10,12),range(30,38)) [(0, 10, 30), (1, 11, 31), (2, None, 32), (3, None, 33), (4, None, 34), (None, None, 35), (None, None, 36), (None, None, 37)] 

puede resolver el problema de esta forma: list(map(lambda x, y: (x, y),[1, 2, 3 ,4, 5], [6, 7, 8, 9, 10]))