tl;博士(鸭子打字)
在所有这些数据结构中看到一些相似之处是正确的。请记住,python 使用鸭子类型(如果它看起来像鸭子并且像鸭子一样嘎嘎叫,那么它就是鸭子)。如果您可以在相同情况下使用两个对象,那么就您当前的意图和目的而言,它们也可能是相同的数据类型。但是您始终必须记住,如果您尝试在其他情况下使用它们,它们的行为可能不再相同。
考虑到这一点,我们应该看一下您提到的四种数据类型的实际不同和相同之处,以大致了解它们可互换的情况。
可变性(你能改变它吗?)
您可以更改字典、列表和集合。元组不能在不复制的情况下“更改”。
可变:dict
, list
,set
不可变:tuple
Pythonstring
也是一种不可变类型。为什么我们想要一些不可变的对象?我将从这个答案中转述:
不可变对象可以优化很多
在 Python 中,只有不可变对象是可散列的(并且只有可散列的对象可以是集合的成员或字典中的键)。
比较这个属性,列表和元组似乎是“最接近”的两种数据类型。在高层次上,元组是列表的不可变“冻结帧”版本。这使得列表对于将随时间变化的数据集非常有用(因为您不必复制列表来修改它),但元组对于字典键(必须是不可变类型)之类的东西很有用。
排序(以及关于抽象数据类型的注释)
字典和集合一样,没有固有的概念顺序。这与确实有顺序的列表和元组形成对比。dict 或 set 中项目的顺序是从程序员那里抽象出来的,这意味着如果元素 A 在for k in mydata
循环中出现在 B 之前,那么一旦开始,您不应该(通常也不能)依赖 A 在 B 之前对mydata
.
保序:list
,tuple
非保序:dict
,set
从技术上讲,如果您连续迭代mydata
两次,它将以相同的顺序进行,但这是 python 机制的一个更方便的功能,而不是set
抽象数据类型的一部分(数据类型的数学定义) . 列表和元组确实保证了顺序,尤其是不可变的元组。
迭代时看到的内容(如果它像鸭子一样走路......)
我想在这里你可以看到一个命名元组,它对每个元素都有一个名称和一个值,作为字典的不可变模拟。但这是一个微不足道的比较 - 请记住,如果您尝试在命名元组上使用仅限字典的方法,则鸭式输入会导致问题,反之亦然。
直接回答您的问题
字典不只是具有特定唯一性约束的元组列表吗?
不,有几个不同之处。字典没有固有的顺序,这与列表不同,后者有。
此外,字典对每个“元素”都有一个键和一个值。另一方面,元组可以有任意数量的元素,但每个元素只有一个值。
由于字典的机制,其中键的作用类似于集合,如果您有键,您可以在恒定时间内查找值。在元组列表(此处为对)中,您需要遍历列表,直到找到键,这意味着搜索将与列表中的元素数量成线性关系。
最重要的是,字典项可以更改,而元组不能。
列表不只是具有不同类型唯一性约束的集合吗?
再次强调,集合没有内在的顺序,而列表有。这使得列表对于表示诸如堆栈和队列之类的东西更加有用,您希望能够记住附加项目的顺序。套装不提供此类保证。然而,它们确实提供了能够在恒定时间内进行成员资格查找的优势,而列表又需要线性时间。
现在有了命名元组——开始感觉更像是一个特例字典。现在有有序的字典——开始感觉更像一个列表。我刚刚看到了一个订购套装的食谱。我可以想象这种情况一直在发生......唯一列表等呢?
在某种程度上我同意你的看法。然而,数据结构库可用于支持已经完善的数据结构的常见用例。这可以防止程序员浪费时间尝试对标准结构进行自定义扩展。只要它没有失控,而且我们仍然可以看到每种解决方案的独特用处,架子上有一个轮子就很好,这样我们就不需要重新发明它了。
Counter() 类就是一个很好的例子。这本专业词典对我的使用次数超出了我的计算(badoom-tshhhhh!),它为我节省了编写自定义解决方案的工作量。我宁愿有一个社区正在帮助我开发和保持适当的 python 最佳实践的解决方案,而不是位于我的自定义数据结构文件夹中并且每年只使用一次或两次的解决方案。