问题的背景
map() 函数源于函数式编程(早在 Lisp 中就出现了),其目的是将函数应用于序列中的每个元素,并返回一个包含结果的新可迭代对象。在 Python 中,它的出现早于生成器和列表表达式,但至今仍被广泛使用,尤其是在大型数据处理管道中。
问题
如果需要根据某个规则修改集合中的每个元素,使用类似 for 循环的解决方案往往会变得冗长且不易阅读。列表表达式和 map() 能够简洁地表达意图。理解这些方法之间的差异是重要的,以便选择合适的工具。
解决方案
map(func, iterable) 创建一个惰性迭代器,其中原始序列的元素被 func 函数转换。map 对象不会立即计算元素,而是惰性工作。def square(x): return x * x squares = map(square, [1, 2, 3]) print(list(squares)) # [1, 4, 9]
列表表达式 [square(x) for x in [1, 2, 3]] 做了同样的事情,但立即返回列表,而生成器表达式 (square(x) for x in [1, 2, 3]) 是一个惰性生成器。
关键特点:
在 Python 3 中,map() 是否返回列表?
不, 从 Python 3 开始,map() 返回的不是列表,而是惰性迭代器。要获取列表,必须手动将结果包装在 list() 中。
res = map(str.upper, ['a', 'b']) print(res) # <map object ...> print(list(res)) # ['A', 'B']
能否在 map() 中添加过滤条件?
不能,map() 不会过滤元素,只会转换。要过滤,请使用 filter() 或列表表达式:
result = map(str.upper, ['a', 'b', None]) # 如果传入 None,map 会引发调用 str.upper(None) 的错误 # filter 有助于在 map 之前去掉 None
能否通过 map() 同时迭代两个序列?
可以,map() 可以接受任意数量的序列,而转换函数必须接收相同数量的参数:
x = [1, 2, 3] y = [10, 20, 30] result = map(lambda a, b: a + b, x, y) print(list(result)) # [11, 22, 33]
开发者期望立即得到列表:
mapped = map(abs, [-1, -2, -3]) print(mapped[1]) # TypeError: 'map' object is not subscriptable
优点:
缺点:
使用生成器表达式来过滤,并使用 map() 来转换:
nums = range(-5, 6) positives = (x for x in nums if x > 0) sq = map(lambda n: n * n, positives) print(list(sq)) # [1, 4, 9, 16, 25, 36]
优点:
缺点: