我在代码战中遇到了一个问题,不确定这两种可能的解决方案之间有什么区别,一种解决方案将列表转换为元组,另一种指定输入列表的元素。
问题:将名称(字符串)列表转换为类似于Facebook用于显示喜欢的语句:“ Alex喜欢这个”,“ Alex和John喜欢这个”,“ Alex,John和另外2个喜欢这个”,等等。
使用if-elif-etc语句,这很简单:
if len(names) == 0:
output_string = "no one likes this"
elif len(names) == 1:
output_string = str(names[0]) + " likes this"
但是在较长的名称列表中,您可以选择:
elif len(names) == 2:
output_string = "%s and %s like this" % (names[0], names[1])
要么
elif len(names) == 3:
output_string = "%s, %s and %s like this" % tuple(names)
我的假设是使用names[0]
等会更有效地计算,因为您没有在元组的内存中创建新对象-是吗?
CPython优化规则通常基于您要花多少时间才能到达C层(与字节码解释器相比)以及字节码指令的复杂程度;对于低水平的绝对工作,解释器的固定开销往往会淹没实际工作,因此,从低级语言的经验中得出的直觉根本不适用。
不过,这非常容易测试,尤其是使用ipython
的%timeit
魔力(在WSLv2下运行的Alpine Linux上,在Python 3.8.5上完成的计时):
In [2]: %%timeit l = [1, 2, 3]
...: tuple(l)
97.6 ns ± 0.303 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [3]: %%timeit l = [1, 2, 3]
...: (l[0], l[1], l[2])
104 ns ± 0.561 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [4]: %%timeit l = [1, 2, 3]
...: (*l,)
78.1 ns ± 0.628 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [5]: %%timeit l = [1, 2]
...: tuple(l)
96 ns ± 0.895 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [6]: %%timeit l = [1, 2]
...: (l[0], l[1])
70.1 ns ± 0.571 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [7]: %%timeit l = [1, 2]
...: (*l,)
73.4 ns ± 0.736 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
因此,实际上,您给出的代码示例为每种大小都做出了正确的决定(假设性能至关重要);在两个元素上,索引比其他方法要快,在三个元素上,tuple
与重复索引相比,批量转换节省了很多钱。
只是为了好玩,我提供了一个等效的解决方案,tuple(l)
即使用附加的拆包概括来构建tuple
使用专用字节码的过程,这表明如何用专用的优化字节码替换通用构造函数调用之类的小事,就可以产生惊人的差异。固定开销。
这个示例的额外乐趣是:更快的(*l,)
解决方案实际上涉及两个临时对象。BUILD_TUPLE_UNPACK
(实现它的字节码)与共享一个代码路径BUILD_LIST_UNPACK
。他们两个实际上都构建了一个list
,BUILD_TUPLE_UNPACK
并将其转换tuple
为末尾。因此(*l,)
,将另一个副本隐藏到临时数据结构中也是如此,但是由于专用字节码比内置查找和通用构造函数代码路径有效得多,因此仍然可以胜任。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句