【问题标题】:Cases where use of tuple is a must必须使用元组的情况
【发布时间】:2012-07-09 02:04:00
【问题描述】:

在 Python 中,我所知道的列表和元组之间的唯一区别是“列表是可变的,但元组不是”。但据我所知,这取决于编码人员是否愿意冒可变性的风险。

所以我想知道是否存在必须在列表上使用元组的情况。用列表做不到但用元组可以做的事情?

【问题讨论】:

  • 元组用于打包/解包返回值。据我所知,列表无法做到这一点。
  • @ltn100:你应该试试。使用任何序列解包工作,包括列表。
  • @Ned:谢谢,我从未将它与其他序列类型一起使用。我天真地认为它是元组的一个特殊属性。
  • 这不是一个真正的答案(因为这个问题似乎是在询问功能),但是当您的结构具有自然限制时(例如 (x, y) 仅限于二维平面时的坐标),应该使用一个元组。 [x, y] 很奇怪。

标签: python list tuples


【解决方案1】:

此外,使用% 运算符的现在已过时的字符串格式要求参数列表是一个元组。列表将被视为单个参数:

>>> "%s + %s" % [1, 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> "%s + %s" % (1, 2)
'1 + 2'

【讨论】:

  • "%s" % [1,2] - 仅当您必须指定 多个 参数时,它才需要 个元组。
【解决方案2】:

@Otto 的回答非常好。我唯一要补充的是,当您打开第 3 方扩展程序时,您确实需要查阅文档。某些函数/方法可能需要一种或另一种数据类型(或根据您使用的数据类型而产生不同的结果)。一个例子是使用元组/列表来索引一个 numpy 数组:

import numpy as np
a=np.arange(50)
a[[1,4,8]] #array([1, 4, 8])
a[(1,4,8)] #IndexError

编辑

此外,快速计时测试表明创建元组比创建列表快得多:

import timeit
t=timeit.timeit('[1,2,3]',number=10000000)
print (t)
t=timeit.timeit('(1,2,3)',number=10000000)
print (t)

记住这一点很好。换句话说,这样做:

for num in (8, 15, 200):
    pass

代替:

for num in [8, 15, 200]:
    pass

【讨论】:

    【解决方案3】:

    您可以将元组用作字典中的键并将元组插入集合中:

    >>> {}[tuple()] = 1
    >>> {}[list()] = 1 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'list'
    

    这基本上是因为 tuple 是可散列的,而 list 不是:

    >>> hash(list())
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'list'
    >>> hash(tuple())
    3527539
    

    【讨论】:

    • 只要确保在将包含它的元组插入到 set/dict 中后不要修改散列计算中使用的字段。这与将可变类型放入集合/字典时的规则相同,但额外的间接层(以及由元组“不可变”引起的混淆)使其不太明显。
    • @Andre:标准的 Python 类型要么是可变的,要么是可散列的。如果您使用自己的类型遵循该约定,则不会遇到此问题。
    • @André 一个类型怎么能同时是可变的和可散列的?从答案中我认为可变类型不可散列?
    • @tarashish 你可以为任何类定义一个__hash__() 函数
    • @tarashish:按照惯例,内置的 Python 类型要么是可变的,要么是可散列的。但是,您可以为任何类型添加 __hash__() 方法。诀窍在于,如果__hash__() 方法依赖于可变字段,则对象的哈希码会随着时间而改变。应该不惜一切代价避免这种情况,因为这意味着您可以创建对象位于dict 中的情况,但是由于对象的字段已更改,因此查找键失败。由于它令人困惑且容易出错,因此最好避免将 __hash__() 函数添加到可变类型。
    猜你喜欢
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    • 2019-12-14
    • 2017-01-23
    • 2017-06-21
    • 2023-03-29
    相关资源
    最近更新 更多