Вопрос-Ответ

How to use filter, map, and reduce in Python 3

Как использовать filter, map и reduce в Python 3

Вот как я привык filter, map и reduce работать в Python 2:

>>> def f(x):
return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

>>> def cube(x):
return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

>>> def add(x,y):
return x+y
>>> reduce(add, range(1, 11))
55

Однако, похоже, что все это не работает в Python 3:

>>> filter(f, range(2, 25))
<filter object at 0x0000000002C14908>

>>> map(cube, range(1, 11))
<map object at 0x0000000002C82B70>

>>> reduce(add, range(1, 11))
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
reduce(add, range(1, 11))
NameError: name 'reduce' is not defined

Почему результаты отличаются? Как я могу заставить код Python 3 работать так же, как код Python 2?


Смотрите также: В чем проблема с reduce()? чтобы узнать конкретную мотивацию для внесения изменений reduce в стандартный библиотечный модуль, а не оставлять его встроенным.

Смотрите Получение map() для возврата списка в Python 3.x для получения более конкретных ответов о map.

Переведено автоматически
Ответ 1

Вы можете прочитать об изменениях в Что нового в Python 3.0. Вам следует внимательно прочитать это при переходе с 2.x на 3.x, поскольку многое изменилось.

Весь ответ здесь - цитаты из документации.

Представления и итераторы вместо списков


Некоторые известные API больше не возвращают списки:



  • [...]

  • map() и filter() возвращать итераторы. Если вам действительно нужен список, быстрое решение - это, например, list(map(...)), но лучшим решением часто является использование понимания списка (особенно когда исходный код использует lambda) или переписывание кода так, чтобы список вообще не требовался. Особенно сложно map() вызывать побочные эффекты функции; правильное преобразование - использовать обычный for цикл (поскольку создание списка было бы просто расточительным).

  • [...]


Встроенные функции



  • [...]

  • Удаленоreduce(). Используйте, functools.reduce() если вам это действительно нужно; однако в 99 процентах случаев явный for цикл более удобочитаем.

  • [...]


Ответ 2

Функциональность map и filter была намеренно изменена для возврата итераторов, а функция reduce была удалена из встроенного и помещена в functools.reduce.

Итак, для filter и map вы можете обернуть их с помощью list(), чтобы увидеть результаты, как вы делали раньше.

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> list(filter(f, range(2, 25)))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> list(map(cube, range(1, 11)))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> import functools
>>> def add(x,y): return x+y
...
>>> functools.reduce(add, range(1, 11))
55
>>>

Теперь рекомендуется заменить использование map и filter выражениями generators или list comprehensions . Пример:

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> [i for i in range(2, 25) if f(i)]
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> [cube(i) for i in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>>

Говорят, что циклы for в 99 процентах случаев читать легче, чем reduce, но я бы просто придерживался functools.reduce.

Редактировать: Цифра в 99 процентов взята непосредственно со страницы Что нового в Python 3.0, автором которой является Гвидо ван Россум.

Ответ 3

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

Быстрая реализация может выглядеть следующим образом:

from contextlib import contextmanager    

@contextmanager
def noiters(*funcs):
if not funcs:
funcs = [map, filter, zip] # etc
from functools import reduce
globals()[reduce.__name__] = reduce
for func in funcs:
globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))
try:
yield
finally:
del globals()[reduce.__name__]
for func in funcs: globals()[func.__name__] = func

С использованием, которое выглядит следующим образом:

with noiters(map):
from operator import add
print(reduce(add, range(1, 20)))
print(map(int, ['1', '2']))

Который выводит:

190
[1, 2]

Всего лишь мои 2 цента :-)

Ответ 4

Поскольку метод reduce был удален из встроенной функции Python3, не забудьте импортировать functools в свой код. Пожалуйста, посмотрите на фрагмент кода ниже.

import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)
python python-3.x