是否有理由更喜欢使用map()而不是列表理解,反之亦然?它们中的任何一个通常比另一个更有效或被认为更python化吗?
当前回答
我用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()
其他回答
我发现列表推导式通常比映射式更能表达我想要做的事情——它们都能完成,但前者节省了试图理解复杂lambda表达式的精神负担。
在某个地方也有一个采访(我不能马上找到),Guido列出lambdas和函数函数是他最后悔接受Python的东西,所以你可以认为它们是非Python的。
我用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。然后,通过将适当的映射函数传递给代码的其余部分,您可能不必修改原始的串行代码以使其并行运行(等等)。
实际上,在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看起来是空的。
总结:
在处理迭代器时,必须记住它们是有状态的,并且在遍历时发生变化。 列表更容易预测,因为只有当你显式地改变它们时,它们才会改变;它们是容器。 还有一个好处:数字、字符串和元组甚至更可预测,因为它们根本不能改变;它们是价值观。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录