是否有理由更喜欢使用map()而不是列表理解,反之亦然?它们中的任何一个通常比另一个更有效或被认为更python化吗?
当前回答
实际上,在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看起来是空的。
总结:
在处理迭代器时,必须记住它们是有状态的,并且在遍历时发生变化。 列表更容易预测,因为只有当你显式地改变它们时,它们才会改变;它们是容器。 还有一个好处:数字、字符串和元组甚至更可预测,因为它们根本不能改变;它们是价值观。
其他回答
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中),如果它们适合你的情况!
我发现列表推导式通常比映射式更能表达我想要做的事情——它们都能完成,但前者节省了试图理解复杂lambda表达式的精神负担。
在某个地方也有一个采访(我不能马上找到),Guido列出lambdas和函数函数是他最后悔接受Python的东西,所以你可以认为它们是非Python的。
性能测量
图片来源:Experfy
你可以自己看看在列表理解和映射函数之间哪个更好。
(与map函数相比,列表理解处理100万条记录所需的时间更少。)
在某些情况下,Map可能会快得多(当您没有为此目的而使用lambda,而是在Map和列表推导中使用相同的函数时)。在其他情况下,列表推导式可能更快,大多数(不是所有)python主义者认为它们更直接、更清晰。
当使用完全相同的函数时,map的微小速度优势的例子:
$ python -m timeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -m timeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop
当map需要lambda时,性能比较完全颠倒的示例:
$ python -m timeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -m timeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop
如果您计划编写任何异步、并行或分布式代码,您可能更喜欢map而不是列表解析——因为大多数异步、并行或分布式包都提供map函数来重载python的map。然后,通过将适当的映射函数传递给代码的其余部分,您可能不必修改原始的串行代码以使其并行运行(等等)。
推荐文章
- python中的assertEquals和assertEqual
- 如何保持Python打印不添加换行符或空格?
- 为什么Python的无穷散列中有π的数字?
- Python 3.7数据类中的类继承
- 如何在PyTorch中初始化权重?
- 计数唯一的值在一列熊猫数据框架像在Qlik?
- 使用Pandas将列转换为行
- 从matplotlib中的颜色映射中获取单个颜色
- 将Pandas或Numpy Nan替换为None以用于MysqlDB
- 使用pandas对同一列进行多个聚合
- 使用Python解析HTML
- django MultiValueDictKeyError错误,我如何处理它
- 如何在for循环期间修改列表条目?
- 我如何在Django中创建一个鼻涕虫?
- 没有名为'django.core.urlresolvers'的模块