Однако, похоже, что все это не работает в Python 3:
>>> filter(f, range(2, 25)) <filterobject at 0x0000000002C14908>
>>> map(cube, range(1, 11)) <mapobject 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'isnot defined
Почему результаты отличаются? Как я могу заставить код Python 3 работать так же, как код Python 2?
Смотрите также: В чем проблема с reduce()? чтобы узнать конкретную мотивацию для внесения изменений reduce в стандартный библиотечный модуль, а не оставлять его встроенным.
Вы можете прочитать об изменениях в Что нового в 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(), чтобы увидеть результаты, как вы делали раньше.
Теперь рекомендуется заменить использование map и filter выражениями generators или list comprehensions . Пример:
>>> deff(x): return x % 2 != 0and x % 3 != 0 ... >>> [i for i inrange(2, 25) if f(i)] [5, 7, 11, 13, 17, 19, 23] >>> defcube(x): return x*x*x ... >>> [cube(i) for i inrange(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 defnoiters(*funcs): ifnot 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: delglobals()[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 в свой код. Пожалуйста, посмотрите на фрагмент кода ниже.