是否有理由更喜欢使用map()而不是列表理解,反之亦然?它们中的任何一个通常比另一个更有效或被认为更python化吗?


当前回答

Python 2:你应该使用map和filter而不是列表推导式。

一个客观的原因是,即使它们不是“Pythonic”,你也应该喜欢它们: 它们需要函数/lambdas作为参数,这引入了一个新的作用域。

我不止一次被这个问题困扰过:

for x, y in somePoints:
    # (several lines of code here)
    squared = [x ** 2 for x in numbers]
    # Oops, x was silently overwritten!

但如果我说:

for x, y in somePoints:
    # (several lines of code here)
    squared = map(lambda x: x ** 2, numbers)

那一切都会好起来的。

你可以说我在相同的作用域中使用相同的变量名是愚蠢的。

我不是。代码本来是好的——两个x不在同一个作用域内。 直到我将内部块移动到代码的不同部分后,问题才出现(即:问题发生在维护期间,而不是开发期间),而且我没有预料到。

是的,如果你从来没有犯过这个错误,那么列表推导式会更优雅。 但从个人经验(以及看到其他人犯同样的错误)来看,我已经见过很多次这样的情况,所以我认为当这些错误渗透到代码中时,不值得你经历这种痛苦。

结论:

使用映射和过滤器。它们可以防止微妙的、难以诊断的范围相关错误。

注:

不要忘记考虑使用imap和filter(在itertools中),如果它们适合你的情况!

其他回答

所以从Python 3开始,map()是一个迭代器,你需要记住你需要什么:一个迭代器或列表对象。

正如@AlexMartelli已经提到的,只有在不使用lambda函数的情况下,map()才比列表理解更快。

我会给你们看一些时间比较。

Python 3.5.2和CPythonI已经使用了Jupiter笔记本电脑,特别是%timeit内置的魔法命令 测量:s == 1000 ms == 1000 * 1000µs = 1000 * 1000 * 1000 ns

设置:

x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))

内置函数:

%timeit map(sum, x_list)  # creating iterator object
# Output: The slowest run took 9.91 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 277 ns per loop

%timeit list(map(sum, x_list))  # creating list with map
# Output: 1000 loops, best of 3: 214 µs per loop

%timeit [sum(x) for x in x_list]  # creating list with list comprehension
# Output: 1000 loops, best of 3: 290 µs per loop

lambda函数:

%timeit map(lambda i: i+1, i_list)
# Output: The slowest run took 8.64 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 325 ns per loop

%timeit list(map(lambda i: i+1, i_list))
# Output: 1000 loops, best of 3: 183 µs per loop

%timeit [i+1 for i in i_list]
# Output: 10000 loops, best of 3: 84.2 µs per loop

还有类似生成器表达式的东西,参见PEP-0289。所以我认为把它添加到比较中是有用的

%timeit (sum(i) for i in x_list)
# Output: The slowest run took 6.66 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 495 ns per loop

%timeit list((sum(x) for x in x_list))
# Output: 1000 loops, best of 3: 319 µs per loop

%timeit (i+1 for i in i_list)
# Output: The slowest run took 6.83 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 506 ns per loop

%timeit list((i+1 for i in i_list))
# Output: 10000 loops, best of 3: 125 µs per loop

你需要列表对象:

如果是自定义函数,则使用列表推导式;如果是内置函数,则使用list(map())

你不需要列表对象,你只需要一个可迭代对象:

总是使用map()!

这里有一个可能的例子:

map(lambda op1,op2: op1*op2, list1, list2)

对比:

[op1*op2 for op1,op2 in zip(list1,list2)]

我猜,如果坚持使用列表推导式而不是映射,那么zip()是一种不幸的、不必要的开销。如果有人能肯定或否定地澄清这一点,那就太好了。

如果您计划编写任何异步、并行或分布式代码,您可能更喜欢map而不是列表解析——因为大多数异步、并行或分布式包都提供map函数来重载python的map。然后,通过将适当的映射函数传递给代码的其余部分,您可能不必修改原始的串行代码以使其并行运行(等等)。

我的用例:

def sum_items(*args):
    return sum(args)


list_a = [1, 2, 3]
list_b = [1, 2, 3]

list_of_sums = list(map(sum_items,
                        list_a, list_b))
>>> [3, 6, 9]

comprehension = [sum(items) for items in iter(zip(list_a, list_b))]

我发现自己开始使用更多的map,我认为map可能比comp慢,因为传递和返回参数,这就是我找到这篇文章的原因。

我相信使用map可以更有可读性和灵活性,特别是当我需要构造列表的值时。

如果你用地图的话,你读的时候就明白了。

def pair_list_items(*args):
    return args

packed_list = list(map(pair_list_items,
                       lista, *listb, listc.....listn))

再加上灵活性奖励。 谢谢你其他的答案,再加上绩效奖金。

实际上,在Python 3语言中,map和list推导式的行为非常不同。看一下下面的Python 3程序:

def square(x):
    return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))

你可能希望它打印“[1,4,9]”这一行两次,但实际上它打印的是“[1,4,9]”后面跟着“[]”。当你第一次看到正方形时,它似乎表现为一个由三个元素组成的序列,但第二次则是一个空的序列。

在Python 2语言中,map返回一个普通的旧列表,就像两种语言中的列表推导一样。关键是Python 3中的map(以及Python 2中的imap)的返回值不是一个列表——它是一个迭代器!

与遍历列表不同,元素是在遍历迭代器时使用的。这就是为什么在最后一个print(list(squares))行中squares看起来是空的。

总结:

在处理迭代器时,必须记住它们是有状态的,并且在遍历时发生变化。 列表更容易预测,因为只有当你显式地改变它们时,它们才会改变;它们是容器。 还有一个好处:数字、字符串和元组甚至更可预测,因为它们根本不能改变;它们是价值观。