为什么在Python中解包(unpacking)会得到一个列表而不是元组?

9

对我来说,这真的很奇怪,因为默认情况下我认为解包操作会产生元组。

在我的情况下,我想使用prefix键进行缓存,所以更喜欢使用元组。

# The r.h.s is a tuple, equivalent to (True, True, 100)
*prefix, seed = ml_logger.get_parameters("Args.attn", "Args.memory_gate", "Args.seed")
assert type(prefix) is list

我原以为解包会返回一个元组。

这里是相关的PEP: https://www.python.org/dev/peps/pep-3132/

-- 更新 --

根据下面的评论和答案,我原本期望解包会返回一个元组,因为在函数参数中,展开参数始终是元组而不是列表。

正如Jason所指出的,在解包过程中无法提前知道结果的长度,因此从实现上讲,万能的捕捉必须从动态附加的列表开始。将其转换为列表大部分时间都是浪费努力。

从语义上讲,我更喜欢保持元组的一致性。


2
在你提供的那份 PEP 中,它提出了一种可迭代解包语法的变化,允许指定一个“捕获所有”名称,该名称将被分配一个列表,其中包含了所有未被分配给“常规”名称的项目。 - Carcigenicate
5
“catch-all”几乎一定要是一个列表:没有一般方法可以预测它有多大(例如,RHS可能是生成器),但必须指定元组的确切大小才能创建。因此,将项目收集到列表中是唯一实际的选择。(该列表后来可以被隐式转换为元组-这在您的情况下很好,但在需要列表并且在绝大多数情况下类型不重要的情况下是完全浪费的努力。) - jasonharper
@jasonharper谢谢你的评论!这有助于澄清当前模式背后的原因。在我看来,这似乎是一种从实现/效率方面向下一个级别的泄漏。从语义层面来看,这些并不是问题所在。 - episodeyang
1个回答

7

这个问题在PEP 3132中提到:

在python-3000邮件列表上进行了简短的讨论[1]后,Guido以其当前形式接受了PEP。可能讨论过的更改包括:[...]

  • 尝试将星号目标赋予与源可迭代对象相同的类型,例如在 a, *b = 'hello' 中,b 将被分配为字符串 'ello'。这看起来很不错,但是无法保证对所有可迭代对象都能正确实现。

  • 将星号目标设置为元组而不是列表。这将与函数的 *args 一致,但会使结果的进一步处理更加困难。

但是,正如您所看到的,这些功能目前尚未实现:

In [1]: a, *b, c = 'Hello!'
In [2]: print(a, b, c)
H ['e', 'l', 'l', 'o'] !

也许,可变列表更适合此类型的解包操作。


1
完成项目中的第一项似乎很困难。我感到惊讶的是,我原本以为第二项是常规操作,因为当我使用扩展参数时,我总是得到元组而不是其他类型的可迭代对象。所以这个概念已经深深烙印在我的大脑皮层中了。 - episodeyang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接