是否有理由更喜欢使用map()而不是列表理解,反之亦然?它们中的任何一个通常比另一个更有效或被认为更python化吗?
当前回答
如果您计划编写任何异步、并行或分布式代码,您可能更喜欢map而不是列表解析——因为大多数异步、并行或分布式包都提供map函数来重载python的map。然后,通过将适当的映射函数传递给代码的其余部分,您可能不必修改原始的串行代码以使其并行运行(等等)。
其他回答
我发现列表推导式通常比映射式更能表达我想要做的事情——它们都能完成,但前者节省了试图理解复杂lambda表达式的精神负担。
在某个地方也有一个采访(我不能马上找到),Guido列出lambdas和函数函数是他最后悔接受Python的东西,所以你可以认为它们是非Python的。
我运行了一个快速测试,比较了调用对象方法的三种方法。在这种情况下,时间差可以忽略不计,这是函数的问题(参见@Alex Martelli的回复)。在这里,我研究了以下方法:
# map_lambda
list(map(lambda x: x.add(), vals))
# map_operator
from operator import methodcaller
list(map(methodcaller("add"), vals))
# map_comprehension
[x.add() for x in vals]
我查看了整数(Python int)和浮点数(Python float)的列表(存储在变量vals中),以增加列表的大小。考虑以下虚拟类DummyNum:
class DummyNum(object):
"""Dummy class"""
__slots__ = 'n',
def __init__(self, n):
self.n = n
def add(self):
self.n += 5
具体来说,就是add方法。__slots__属性是Python中的一个简单优化,用于定义类(属性)所需的总内存,减少内存大小。 这里是结果图。
如前所述,所使用的技术只会产生最小的差异,您应该以对您来说最易读的方式进行编码,或者在特定的情况下进行编码。在这种情况下,列表理解(map_comprehension技术)对于对象中的两种类型的添加是最快的,特别是对于较短的列表。
访问这个粘贴文件以获取用于生成图表和数据的源。
我用perfplot(我的一个项目)计算了一些结果。
正如其他人所注意到的,map实际上只返回一个迭代器,因此它是一个常量时间操作。当通过list()实现迭代器时,它与列表推导式相当。根据不同的表达方式,任何一种都可能有轻微的优势,但并不显著。
注意,像x ** 2这样的算术运算在NumPy中要快得多,特别是如果输入数据已经是NumPy数组的话。
hex:
X ** 2:
代码重现图:
import perfplot
def standalone_map(data):
return map(hex, data)
def list_map(data):
return list(map(hex, data))
def comprehension(data):
return [hex(x) for x in data]
b = perfplot.bench(
setup=lambda n: list(range(n)),
kernels=[standalone_map, list_map, comprehension],
n_range=[2 ** k for k in range(20)],
equality_check=None,
)
b.save("out.png")
b.show()
import perfplot
import numpy as np
def standalone_map(data):
return map(lambda x: x ** 2, data[0])
def list_map(data):
return list(map(lambda x: x ** 2, data[0]))
def comprehension(data):
return [x ** 2 for x in data[0]]
def numpy_asarray(data):
return np.asarray(data[0]) ** 2
def numpy_direct(data):
return data[1] ** 2
b = perfplot.bench(
setup=lambda n: (list(range(n)), np.arange(n)),
kernels=[standalone_map, list_map, comprehension, numpy_direct, numpy_asarray],
n_range=[2 ** k for k in range(20)],
equality_check=None,
)
b.save("out2.png")
b.show()
这里有一个可能的例子:
map(lambda op1,op2: op1*op2, list1, list2)
对比:
[op1*op2 for op1,op2 in zip(list1,list2)]
我猜,如果坚持使用列表推导式而不是映射,那么zip()是一种不幸的、不必要的开销。如果有人能肯定或否定地澄清这一点,那就太好了。
如果您计划编写任何异步、并行或分布式代码,您可能更喜欢map而不是列表解析——因为大多数异步、并行或分布式包都提供map函数来重载python的map。然后,通过将适当的映射函数传递给代码的其余部分,您可能不必修改原始的串行代码以使其并行运行(等等)。
推荐文章
- 如何更新SQLAlchemy行条目?
- name 'reduce'在Python中没有定义
- 如何计算一个NumPy bool数组中的真实元素的数量
- 在python中,在函数结束(例如检查失败)之前退出函数(没有返回值)的最佳方法是什么?
- 在Python中检查一个单词是否在字符串中
- Python glob多个文件类型
- 如何可靠地打开与当前运行脚本在同一目录下的文件
- Python csv字符串到数组
- 如何在Python中进行热编码?
- 如何嵌入HTML到IPython输出?
- 在Python生成器上使用“send”函数的目的是什么?
- 是否可以将已编译的.pyc文件反编译为.py文件?
- Django模型表单对象的自动创建日期
- 在Python中包装长行
- 如何计算两个时间串之间的时间间隔