Python 中模块级常量的元组与列表?

Tuples vs lists for module-level constants in Python?

在 Python 中使用元组而不是列表作为模块级常量可迭代对象的风格好吗?例如,我的文件顶部有一个重要字符串列表,我需要在输入中查找这些字符串:

IMPORTANT_STRINGS = [
  "Hello world!",
  "Goodbye world!",
  "Foo...",
  # etc --- there are about 40 entries
]
当我的程序是 运行 时,

IMPORTANT_STRINGS 永远不会被修改。

一方面,我认为不变性很好,我应该尽可能地使用不可变数据结构,所以我应该改用元组。

另一方面,我认为元组不仅仅是不可变的列表:它们适用于异构集合,当您传递成对、三元组等东西时应该使用它们——固定大小大小对它们是什么很重要的东西。我也不认为我曾经见过 Python 代码在野外使用元组作为这样的常量,我的眼睛看起来真的很奇怪说:

IMPORTANT_STRINGS = (
   "Hello world!",
   etc
 )

我会选择元组。元组更快、不可变,而且——正因如此——更安全。为什么你想要一个可变类型的东西应该是不可变的?

"tuples are for heterogenous collections" 的说法对我来说毫无意义。列表也可以存储异构元素。 tuples = heterogeneous 和 lists = homogeneous 的假设只是一个概括,通常你想要一个列表遍历元素并以类似的方式使用它们(如果不完全以相同的方式至少以多态方式)

另一方面,元组在某种意义上有点类似于结构,用于存储在您正在编码的模型中具有某种关系的值,并且以这种方式与异构元素相关,但为什么不能'他们不是同一类型吗?例如,一个 3 维向量将表示为一个元组(至少是最直观的方式)但它仅由 3 个数字组成,我们是否应该使用列表因为它们相同?

创建一个模块,将其命名为 foo.py 并插入以下内容:

FOO = 'a', 'b'
BAR = ['a', 'b']

现在导入它们并查看它们如何响应就地操作:

>>> import foo
>>> from foo import FOO, BAR
>>> FOO += 'c', 'd'
>>> BAR += 'c', 'd'
>>> FOO
('a', 'b', 'c', 'd')
>>> foo.FOO
('a', 'b')
>>> foo.BAR
['a', 'b', 'c', 'd']

正如我们所见,FOO 元组作为 foo 模块中的规范集合保持其原始状态。 BAR 另一方面,可以变异。

你更喜欢哪个?

这取决于您希望其他模块访问集合时发生什么。在许多情况下,我们希望其他模块能够添加到规范列表中。在某些情况下,我们不会。答案是根据您的情况以及设计和使用的目的和意图做适当的事情。

在你的情况下,你说:

IMPORTANT STRINGS will never be modified while my program is running.

如果它们从不应该被修改,那么元组就可以了。如果您希望您的代码对可能需要在同一进程中共享数据的其他人有用,那么您应该使用列表。

你提到:

I think that tuples are more than just immutable lists: they're for heterogenous collections that should be used when you're passing around things like pairs, triples, etc --- fixed-size things whose size is important to what they are.

元组本质上是不可变的列表,列表中也可以包含各种对象。是的,固定大小,但这实际上只是不变性的直接结果。

你应该使用元组作为不可变列表吗?我不会。我会根据我的代码的用户负责的理论使用列表,并且可以处理来自他们未编写的模块的修改列表。

请注意,如上所述,使用元组扩展列表的能力意味着您通常可以从元组开始,然后根据需要移动到列表。

只是为了反驳论点,__all__ 列表 的 public 个对象,模块将在以下情况下导出: from <module> import * 使用.

这基本上是模块级常量字符串的集合(就像您拥有的那样),但在整个标准库中作为列表实现。快速测试确认 tuple 也适用于此,但它到处都是列表。