list() 与 Python 3.5+ 中的可迭代解包

问题描述 投票:0回答:5

在支持后者的 Python 版本中,

list(iterable)
[*iterable]
之间有任何实际区别吗?

python python-3.x list iterable python-internals
5个回答
7
投票

list(x)
是函数,
[*x]
是表达式。您可以重新分配
list
,并使其执行其他操作(但您不应该这样做)。

谈论 cPython,

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)

所以你可以说

[*a]
可能 稍微更有效,但也只是稍微有效一点。


4
投票

您可以使用标准库模块

dis
来研究函数生成的字节码。在这种情况下:

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
到底是做什么的。

请注意,两者实际上比为此编写标准列表理解要少得多的代码:

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

1
投票

由于

[*iterable]
正在解包,因此它接受 类似赋值 语法,与
list(iterable)
不同:

>>> [*[]] = []
>>> list([]) = []
  File "<stdin>", line 1
SyntaxError: can't assign to function call

您可以在这里阅读更多相关信息(虽然没有用)。

您还可以使用

list(sequence=iterable)
,即使用关键字参数:

>>> list(sequence=[])
[]

再次没用


1
投票

执行相同操作的两个构造之间总会存在一些差异。事实是,我不会说这种情况下的差异实际上是“实用的”。两者都是采用可迭代对象、迭代它然后从中创建列表的表达式。 契约是相同的:输入是可迭代的,输出是由可迭代元素填充的列表。

是的,

list

可以反弹到不同的名称;

list(it)
是函数调用,
[*it]
是列表显示;对于较小的可迭代对象,
[*it]
速度更快,但通常对于较大的可迭代对象执行相同的操作。哎呀,人们甚至可以提出这样一个事实:
[*it]
减少了三个击键。

这些实用吗?当我尝试从可迭代对象中获取列表时,我会想到它们吗?好吧,也许击键是为了保持在 79 个字符以下,并让 linter 将其关闭。


1
投票

things = list( get_things( numerous and long arguments, ) )

而 [*] 语法通过将代码缩短为
来节省两行和缩进级别

[*things] = get_things( numerous and long arguments, )

	
© www.soinside.com 2019 - 2024. All rights reserved.