>>>def f(x):return x %2!=0and 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'isnot defined
>>> 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
I would appreciate if someone could explain to me why this is.
map() and filter() return iterators. If you really need a list, a quick fix is e.g. list(map(...)), but a better fix is often to use a list comprehension (especially when the original code uses lambda), or rewriting the code so it doesn’t need a list at all. Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).
>>>def f(x):return x %2!=0and 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的用法。例:
>>>def f(x):return x %2!=0and 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]>>>
The functionality of map and filter was intentionally changed to return iterators, and reduce was removed from being a built-in and placed in functools.reduce.
So, for filter and map, you can wrap them with list() to see the results like you did before.
As an addendum to the other answers, this sounds like a fine use-case for a context manager that will re-map the names of these functions to ones which return a list and introduce reduce in the global namespace.
A quick implementation might look like this:
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 a usage that looks like this:
with noiters(map):
from operator import add
print(reduce(add, range(1, 20)))
print(map(int, ['1', '2']))
Since the reduce method has been removed from the built in function from Python3, don’t forget to import the functools in your code. Please look at the code snippet below.
The reduce function, since it is not commonly used, was removed from the built-in functions in Python 3. It is still available in the functools module, so you can do:
def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):return list(
filter(lambda x: x !=[],
map(lambda x: x[0]if city in x[1]else[], flight_destinations_dict.items())))
One of the advantages of map, filter and reduce is how legible they become when you “chain” them together to do something complex. However, the built-in syntax isn’t legible and is all “backwards”. So, I suggest using the PyFunctional package (https://pypi.org/project/PyFunctional/).
Here’s a comparison of the two:
“I have a sequence of flight destinations. Out of which I want to get
the dict key if city is in the dict values. Finally, filter out the
empty lists I created in the process.”
from functional import seq # PyFunctional package to allow easier syntax
def find_return_flights_PYFUNCTIONAL_SYNTAX(city, flight_destinations_dict):
return seq(flight_destinations_dict.items()) \
.map(lambda x: x[0] if city in x[1] else []) \
.filter(lambda x: x != []) \
Default Python version
It’s all backwards. You need to say:
“OK, so, there’s a list. I want to filter empty lists out of it. Why?
Because I first got the dict key if the city was in the dict values.
Oh, the list I’m doing this to is flight_destinations_dict.”
def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):
return list(
filter(lambda x: x != [],
map(lambda x: x[0] if city in x[1] else [], flight_destinations_dict.items())
)
)