Подтвердить что ты не робот

Python 3 против поведения карты Python 2

В Python 2 общая (старая, устаревшая) идиома должна использовать map для объединения итераторов с неравномерной длиной, используя форму map(None,iter,iter,...) следующим образом:

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

В Python 2 он расширен так, что самый длинный итератор - это длина возвращаемого списка, а если он короче другого, то он дополняется None.

В Python 3 это другое. Во-первых, вы не можете использовать None в качестве аргумента для вызываемого в позиции 1:

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

ОК - я могу исправить это так:

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

Но теперь у меня другая проблема: map возвращает кратчайшую длину итератора - больше не заполняется с помощью None.

Поскольку я переношу код Python 2 на Python 3, это не ужасная редкая идиома, и я не понял легкое решение на месте.

К сожалению, утилиты 2to3 не выбрали, не предлагая:

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

Предложения?


Изменить

Существует некоторое обсуждение того, насколько распространена эта идиома. См. этот пост..

Я обновляю устаревший код, написанный, когда я еще учился в старшей школе. Посмотрите на учебники Python 2003 года, в которых написано и обсуждено Раймондом Хеттингером с указанным конкретным поведением отображения карты...

4b9b3361

Ответ 1

На этот раз я отвечу на свой вопрос.

С Python 3x вы можете использовать itertools.zip_longest так:

>>> 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)]

Вы также можете перевести ur own, я полагаю:

>>> 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)]

Ответ 2

itertools.zip_longest делает то, что вы хотите, с более понятным именем.:)

Ответ 3

вы можете решить эту проблему следующим образом: list(map(lambda x, y: (x, y),[1, 2, 3 ,4, 5], [6, 7, 8, 9, 10]))