繁体   English   中英

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

[英]list() vs iterable unpacking in Python 3.5+

在支持后者的 Python 版本中, list(iterable)[*iterable]之间有什么实际区别吗?

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]可能稍微更有效率,但稍微有效一点。

您可以使用标准库模块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

由于[*iterable]是解包的,它接受类似赋值的语法,与list(iterable)

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

您可以在此处阅读有关此内容的更多信息(尽管没有用)。

您还可以使用list(sequence=iterable) ,即带有关键字参数:

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

又没

做同样事情的两个结构之间总会有一些差异。 问题是,我不会说这种情况下的差异实际上是实用的 两者都是获取可迭代对象的表达式,遍历它然后从中创建一个列表。

契约是相同的:输入是一个可迭代的输出是一个由可迭代元素填充的列表。

是的, list可以反弹到不同的名称; list(it)是一个函数调用,而[*it]是一个列表显示; [*it]使用较小的可迭代对象更快,但通常使用较大的可迭代对象执行相同的操作。 哎呀,甚至可以抛出这样一个事实,即[*it]少了三个击键。

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

显然,在 CPython 中存在性能差异,其中[*a]过度分配而list()不会: 是什么导致 [*a] 过度分配?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM