在支持list(iterable)
和[*iterable]
的Python版本中,它们之间是否有实际区别?
答案 0 :(得分:4)
def list_comp(x):
return [a for a in x]
dis.dis(list_comp)
# 2 0 LOAD_CONST 1 (<code object <listcomp> at 0x7f65356198a0, file "<ipython-input-46-dd71fb182ec7>", line 2>)
# 2 LOAD_CONST 2 ('list_comp.<locals>.<listcomp>')
# 4 MAKE_FUNCTION 0
# 6 LOAD_FAST 0 (x)
# 8 GET_ITER
# 10 CALL_FUNCTION 1
# 12 RETURN_VALUE
是一个函数,list(x)
是一个表达式。您可以重新分配[*x]
,并使其做其他事情(但不应该这样做)。
谈论cPython,list
转换为以下字节码序列:
b = list(a)
相反,LOAD_NAME 1 (list)
LOAD_NAME 0 (a)
CALL_FUNCTION 1
STORE_NAME 2 (b)
变为:
c = [*a]
因此您可以辩称LOAD_NAME 0 (a)
BUILD_LIST_UNPACK 1
STORE_NAME 3 (c)
可能效率更高,但略有提高。
答案 1 :(得分:3)
您可以使用标准库模块dis
来调查函数生成的字节码。在这种情况下:
place.getLatLng()
所以有一个区别,不仅是全局定义名称import dis
def call_list(x):
return list(x)
def unpacking(x):
return [*x]
dis.dis(call_list)
# 2 0 LOAD_GLOBAL 0 (list)
# 2 LOAD_FAST 0 (x)
# 4 CALL_FUNCTION 1
# 6 RETURN_VALUE
dis.dis(unpacking)
# 2 0 LOAD_FAST 0 (x)
# 2 BUILD_LIST_UNPACK 1
# 4 RETURN_VALUE
的加载,而且解压缩时不需要这样做。因此,归结为如何定义内置list
函数以及list
的作用。
请注意,两者实际上都比编写标准列表理解代码少得多:
BUILD_LIST_UNPACK
答案 2 :(得分:0)
由于[*iterable]
正在解压缩,它接受类似于 assignment 的语法,与list(iterable)
不同:
>>> [*[]] = []
>>> list([]) = []
File "<stdin>", line 1
SyntaxError: can't assign to function call
您可以阅读有关此here的更多信息(虽然没有用)。
您还可以使用list(sequence=iterable)
,即带有关键字参数:
>>> list(sequence=[])
[]
再次not useful。
答案 3 :(得分:0)
在做相同事情的两个结构之间总会有一些差异。问题是,我不会说这种情况下的差异实际上是实践。两者都是采用可迭代的表达式,对其进行迭代,然后从中创建一个列表。
合同是相同的:输入是可迭代的输出是由iterables元素填充的列表。
是的,list
可以反弹到另一个名称; list(it)
是函数调用,而[*it]
是列表显示; [*it]
使用较小的可迭代项时速度更快,但通常使用较大的迭代器时具有相同的性能。哎呀,甚至可以说[*it]
少了三击。
这些实用吗?尝试从迭代列表中获取清单时,我会想到它们吗?好吧,也许击键是为了保持在79个字符以下,并让lint将其关闭。
答案 4 :(得分:0)
显然在CPython中存在性能差异,其中 [* a] 进行整体分配,而 list()则没有:What causes [*a] to overallocate?