Comment utiliser filter, map, and reduce en Python 3

filter , map , et reduce fonctionne parfaitement en Python 2. Voici un exemple:

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

mais en Python 3, je reçois les sorties suivantes:

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

j'apprécierais que quelqu'un puisse m'expliquer pourquoi.

Capture d'écran de code pour plus de clarté:

IDLE sessions of Python 2 and 3 side-by-side

229
demandé sur poke 2012-11-30 08:12:53

4 réponses

vous pouvez lire à propos des changements dans Quoi de neuf en Python 3.0 . Vous devriez le lire attentivement lorsque vous déplacez de 2.x à 3.x depuis beaucoup de choses ont changé.

toute la réponse ici sont des citations de la documentation.

Vues Et Itérateurs Au Lieu Des Listes

certaines API bien connues ne renvoient plus de listes:

  • [...]
  • map() et filter() itérateurs de retour. Si vous avez vraiment besoin d'une liste, une solution rapide est par exemple list(map(...)) , mais une meilleure solution est souvent d'utiliser une compréhension de liste (surtout lorsque le code original utilise lambda), ou réécrire le code de sorte qu'il n'a pas besoin d'une liste du tout. Particulièrement délicat est map() invoqué pour les effets secondaires de la fonction; le la transformation correcte consiste à utiliser une boucle régulière for (puisque créer une liste serait juste un gaspillage).
  • [...]

objets internes

  • [...]
  • supprimé reduce() . Utiliser functools.reduce() si vous en avez vraiment besoin; cependant, 99% du temps une la boucle explicite for est plus lisible.
  • [...]
268
répondu nhahtdh 2012-11-30 04:22:03

la fonctionnalité de map et filter a été modifiée intentionnellement pour retourner les itérateurs, et reduce a été retiré du fait qu'il s'agissait d'un système intégré et placé dans functools.reduce .

ainsi, pour filter et map , vous pouvez les envelopper avec list() pour voir les résultats comme vous l'avez fait avant.

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

la recommandation est maintenant que vous remplaciez votre utilisation de map et de filter par des expressions ou des listes de générateurs compréhension. Exemple:

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

ils disent que pour les boucles sont 99 pour cent du temps plus facile à lire que de réduire, Mais je m'en tiendrais simplement à functools.reduce .

Edit : le chiffre de 99% est tiré directement de la page Quoi de neuf en Python 3.0 de Guido van Rossum.

69
répondu Joshua D. Boyd 2016-07-25 06:48:31

comme addendum aux autres réponses, cela ressemble à un cas d'utilisation pour un gestionnaire de contexte qui va re-map les noms de ces fonctions à ceux qui renvoient une liste et introduisent reduce dans l'espace de noms global.

une implémentation rapide pourrait ressembler à ceci:

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

avec un usage qui ressemble à ceci:

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

qui imprime:

190
[1, 2]

juste mes 2 cents :- )

7
répondu Jim Fasarakis Hilliard 2016-08-31 09:50:18

depuis que la méthode reduce a été retirée de la fonction intégrée de Python3, n'oubliez pas d'importer le functools dans votre code. Veuillez consulter l'extrait de code ci-dessous.

import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)
3
répondu Bikash Singh 2018-06-25 04:23:03