Cómo usar filtrar, mapear y reducir en Python 3


filter, map, y reduce funcionan perfectamente en Python 2. He aquí un ejemplo:

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

Pero en Python 3, recibo las siguientes salidas:

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

Agradecería que alguien me explicara por qué es esto.

Captura de pantalla del código para mayor claridad:

Sesiones inactivas de Python 2 y 3 lado a lado

Author: poke, 2012-11-30

4 answers

Puedes leer sobre los cambios en Qué hay De Nuevo En Python 3.0. Usted debe leer a fondo cuando se mueve de 2.x a 3.x desde que mucho ha cambiado.

La respuesta completa aquí son citas de la documentación.

Vistas E Iteradores En Lugar De Listas

Algunas API bien conocidas ya no devuelven listas:

  • [...]
  • map() y filter() el retorno de los iteradores. Si realmente necesitas un list, una solución rápida es, por ejemplo, list(map(...)), pero una mejor solución es a menudo usar una comprensión de lista (especialmente cuando el código original usa lambda), o reescribir el código para que no necesite una lista en absoluto. Particularmente difícil es map() invocado para los efectos secundarios de la función; la transformación correcta es utilizar un bucle regular for (ya que crear una lista sería un desperdicio).
  • [...]

Builtins

  • [...]
  • Eliminado reduce(). Uso functools.reduce() si realmente lo necesita; sin embargo, el 99 por ciento de las veces un bucle for explícito es más legible.
  • [...]
 268
Author: nhahtdh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-30 04:22:03

La funcionalidad de map y filter se cambió intencionalmente para devolver iteradores, y reduce se eliminó de ser un built-in y se colocó en functools.reduce.

Entonces, para filter y map, puedes envolverlos con list() para ver los resultados como lo hiciste antes.

>>> 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 recomendación ahora es que reemplace su uso de mapa y filtro con expresiones generators o comprensiones de listas. Ejemplo:

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

Dicen que los bucles for son el 99 por ciento de las veces más fáciles de leer que reducir, pero me quedaría con functools.reduce.

Editar : La cifra del 99 por ciento se extrae directamente de la página Qué hay de nuevo En Python 3.0 escrita por Guido van Rossum.

 69
Author: Joshua D. Boyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-25 06:48:31

Como un anexo a las otras respuestas, esto suena como un buen caso de uso para un administrador de contexto que reasignará los nombres de estas funciones a las que devuelven una lista e introducirán reduce en el espacio de nombres global.

Una implementación rápida podría verse así:

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

Con un uso que se parece a esto:

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

Que imprime:

190
[1, 2]

Solo mis 2 centavos: -)

 7
Author: Jim Fasarakis Hilliard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-31 09:50:18

Dado que el método reduce ha sido eliminado de la función incorporada de Python3, no olvide importar el functools en su código. Por favor, mira el fragmento de código a continuación.

import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)
 3
Author: Bikash Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-25 04:23:03