Получение карты () для возврата списка в Python 3.x - PullRequest
447 голосов
/ 20 августа 2009

Я пытаюсь отобразить список в гекс, а затем использовать список в другом месте. В Python 2.6 это было легко:

A: Python 2.6:

>>> map(chr, [66, 53, 0, 94])
['B', '5', '\x00', '^']

Однако в Python 3.1 вышеприведенное возвращает объект карты.

B: Python 3.1:

>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>

Как мне получить сопоставленный список (как в A выше) в Python 3.x?

В качестве альтернативы, есть ли лучший способ сделать это? Мой начальный объект списка содержит около 45 элементов, и я хотел бы преобразовать их в шестнадцатеричные.

Ответы [ 9 ]

666 голосов
/ 20 августа 2009

Сделайте это:

list(map(chr,[66,53,0,94]))

В Python 3+ многие процессы, которые выполняют итерации, возвращают сами итераторы. В большинстве случаев это приводит к экономии памяти и должно ускорить процесс.

Если все, что вы собираетесь сделать, это в конечном итоге перебрать этот список, нет необходимости даже конвертировать его в список, потому что вы все равно можете перебирать объект map следующим образом:

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)
89 голосов
/ 20 августа 2009

Почему ты этого не делаешь:

[chr(x) for x in [66,53,0,94]]

Это называется пониманием списка. Вы можете найти много информации в Google, но вот ссылка на документацию по Python (2.6) по спискам . Возможно, вас больше заинтересует документация по Python 3 .

78 голосов
/ 01 августа 2016

Новое и аккуратное в Python 3.5:

[*map(chr, [66, 53, 0, 94])]

Благодаря Дополнительные обобщения распаковки

UPDATE

Всегда ища более короткие пути, я обнаружил, что этот тоже работает:

*map(chr, [66, 53, 0, 94]),

Распаковка работает и в кортежах. Обратите внимание на запятую в конце. Это делает его кортежем из 1 элемента. То есть это эквивалентно (*map(chr, [66, 53, 0, 94]),)

Он короче всего на один символ из версии со списочными скобками, но, на мой взгляд, лучше написать, потому что вы начинаете прямо со звездочки - синтаксиса расширения, так что я чувствую, что он мягче в уме. :)

22 голосов
/ 01 июля 2014

Функция отображения списка с возвратом имеет преимущество сохранения набора текста, особенно во время интерактивных сеансов. Вы можете определить функцию lmap (по аналогии с imap в python2), которая возвращает список:

lmap = lambda func, *iterable: list(map(func, *iterable))

Тогда вызов lmap вместо map сделает работу: lmap(str, x) короче на 5 символов (в данном случае 30%), чем list(map(str, x)), и, безусловно, короче [str(v) for v in x]. Вы можете создать аналогичные функции и для filter.

Был комментарий к оригинальному вопросу:

Я бы предложил переименовать в Getting map (), чтобы получить список в Python 3. *, так как он применяется ко всем версиям Python3. Есть ли способ сделать это? - meawoppl 24 января в 17: 58

Это возможно , но это очень плохая идея. Просто для забавы, вот как вы можете (, но не ) делать это:

__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator
10 голосов
/ 20 августа 2009

Я не знаком с Python 3.1, но будет ли это работать?

[chr(x) for x in [66, 53, 0, 94]]
3 голосов
/ 08 ноября 2017

Преобразование мой старый комментарий для лучшей наглядности: для "лучшего способа сделать это" без map полностью, если известно, что ваши входные данные являются ординалами ASCII, обычно гораздо быстрее преобразовать в bytes и декодировать, а-ля bytes(list_of_ordinals).decode('ascii'). Это дает вам str значений, но если вам нужно list для изменчивости или чего-то подобного, вы можете просто преобразовать его (и это все еще быстрее). Например, в ipython микробенчмарках, конвертирующих 45 входных данных:

>>> %%timeit -r5 ordinals = list(range(45))
... list(map(chr, ordinals))
...
3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*map(chr, ordinals)]
...
3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*bytes(ordinals).decode('ascii')]
...
1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... bytes(ordinals).decode('ascii')
...
781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

Если вы оставите его как str, это займет ~ 20% времени самых быстрых map решений; даже если вернуться к списку, это все равно менее 40% самого быстрого решения map. Массовое преобразование через bytes и bytes.decode, а затем массовое преобразование обратно в list экономит много работы, , но, как отмечалось, , работает, только если все ваши входные данные являются ASCII-ординалами (или порядковыми числами в некотором одном байте для каждой конкретной кодировки символов, например latin-1).

1 голос
/ 11 ноября 2018

Используя списочное понимание в Python и утилиту базовой функции карты, можно сделать это также:

chi = [x for x in map(chr,[66,53,0,94])]

1 голос
/ 15 июня 2018

В дополнение к ответам выше в Python 3, мы можем просто создать list значений результата из map как

li = []
for x in map(chr,[66,53,0,94]):
    li.append(x)

print (li)
>>>['B', '5', '\x00', '^']

Мы можем обобщить на другом примере, где меня поразили, операции с картой также могут выполняться аналогично, как в задаче regex, мы можем написать функцию для получения list элементов для отображения и получения набора результатов на в то же время. Ex.

b = 'Strings: 1,072, Another String: 474 '
li = []
for x in map(int,map(int, re.findall('\d+', b))):
    li.append(x)

print (li)
>>>[1, 72, 474]
1 голос
/ 07 ноября 2017
list(map(chr, [66, 53, 0, 94]))

map (func, * iterables) -> объект карты Сделайте итератор, который вычисляет функцию, используя аргументы из каждый из повторяемых. Останавливается, когда самая короткая итерация исчерпана.

"Сделай итератор"

означает, что он вернет итератор.

"который вычисляет функцию, используя аргументы из каждого из итераций"

означает, что функция next () итератора будет принимать одно значение каждого итерируемого элемента и передавать каждое из них одному позиционному параметру функции.

Таким образом, вы получаете итератор из функции map () и jsut передаете его встроенной функции list () или используете понимание списка.

...