关于集合:为什么Python将元组,列表,集合和字典视为根本不同的东西?

Why does Python treat tuples, lists, sets and dictionaries as fundamentally different things?

我喜欢Python的原因之一是元组、列表、集合和字典提供的表达能力/减少的编程工作量。一旦你理解了清单的理解和一些基本模式的使用和为,生活会变得更好!Python摇滚。

然而,我想知道为什么这些构造被视为与它们不同,以及随着时间的推移这是如何变化的(变得越来越陌生)。回到python 2.x,我可以提出这样一个论点:它们都是基本集合类型的变体,有些非异国情调的用例要求您将字典转换为列表,然后再转换回来,这有点令人恼火。(字典不只是具有特定唯一性约束的元组列表吗?列表是否只是一个具有不同类型唯一性约束的集合?).

现在在3.x的世界里,情况变得更复杂了。现在有了命名的元组——开始感觉更像是一个特殊情况字典。现在有了有序的字典——开始觉得更像是一个列表。我刚看到一份定做套装的食谱。我可以想象这种情况不断发生…唯一的列表等如何?

python的禅宗说"应该有一种——最好只有一种——显而易见的方法"。在我看来,这种丰富的专门集合类型与这个Python规则相冲突。

硬核的Python派怎么想?


这些数据类型都有不同的用途,在理想的环境中,您可能能够更统一它们。然而,在现实世界中,我们需要对基本集合进行有效的实现,例如,排序会增加运行时惩罚。

命名的元组主要用于使stat()等的接口更可用,并且在处理SQL行集时也很好。

您要寻找的大统一实际上是以不同的访问协议(getitem、getattr、iter,…)的形式存在的,这些类型根据其预期目的混合和匹配。


tl;dr(鸭子打字)

在所有这些数据结构中看到一些相似之处是正确的。记住,Python使用鸭子打字(如果它看起来像鸭子,嘎嘎叫起来像鸭子,那么它就是鸭子)。如果您可以在相同的情况下使用两个对象,那么为了您当前的目的和目的,它们也可能是相同的数据类型。但是你必须时刻记住,如果你试图在其他情况下使用它们,它们可能不再以同样的方式工作。好的。

考虑到这一点,我们应该看看您提到的四种数据类型的实际差异和相同之处,以大致了解它们可以互换的情况。好的。易变性(你能改变它吗?)

您可以更改字典、列表和集合。如果不复制元组,就不能"更改"。好的。

  • 可变:dictlistset。好的。

    不变:tuple。好的。

python string也是不可变的类型。为什么我们需要一些不变的对象?我会从这个答案中转述:好的。

  • Immutable objects can be optimized a lot

    Ok.

  • In Python, only immutables are hashable (and only hashable objects can be members of sets, or keys in dictionaries).

    Ok.

  • 通过比较这个属性,列表和元组看起来像是"最近"的两种数据类型。在高层,元组是列表的不可变"冻结帧"版本。这使得列表对于将随时间变化的数据集很有用(因为您不必复制列表来修改它),但元组对于字典键(必须是不可变类型)之类的东西很有用。好的。排序(以及关于抽象数据类型的注释)

    字典和集合一样,没有固有的概念顺序。这与列表和元组形成了对比,它们确实有顺序。口述或集合中的项目顺序是从程序员那里抽象出来的,这意味着如果元素a在for k in mydata循环中位于b之前,那么一旦开始对mydata进行更改,就不应该(并且一般不能)依赖于a在b之前。好的。

    • 订单保存:listtuple。好的。

      非订单保存:dictset。好的。

    从技术上讲,如果您连续两次迭代mydata,它的顺序是相同的,但这是python机制的一个更方便的特性,而不是set抽象数据类型(数据类型的数学定义)的一部分。列表和元组确实保证了顺序,尤其是不可变的元组。好的。迭代时看到的内容(如果它像鸭子一样走…)

    • 每个元素一个"项目":setlisttuple。好的。

      每个元素有两个"项目":dict。好的。

    我想在这里您可以看到一个命名的元组,它对每个元素都有一个名称和一个值,就像一个不可变的字典。但这是一个微不足道的比较——请记住,如果您试图对一个命名的元组使用仅限字典的方法,那么duck类型会导致问题,反之亦然。好的。直接回答你的问题

    Isn't a dictionary just a list of tuples with a particular uniqueness
    constraint?

    Ok.

    不,有几个不同之处。字典没有固有的顺序,这与列表不同,它有。好的。

    此外,字典对每个"元素"都有一个键和一个值。另一方面,元组可以有任意数量的元素,但每个元素只能有一个值。好的。

    由于字典的机制,其中键的作用类似于一个集合,所以如果您有键,可以在固定时间内查找值。在一个元组列表(这里是成对的)中,您需要遍历该列表直到找到键,这意味着搜索将在列表中元素的数量上是线性的。好的。

    最重要的是,字典项可以更改,而元组不能更改。好的。

    Isn't a list just a set with a different kind of uniqueness
    constraint?

    Ok.

    再次强调,集合没有固有的顺序,而列表有。这使得列表对于表示堆栈和队列之类的东西更有用,因为您希望能够记住附加项的顺序。SETS不提供这样的保证。然而,它们提供了能够在恒定时间内进行成员查找的优势,而列表也需要线性时间。好的。

    There are now named tuples -- starting to feel more like a special-case dictionary. There are now ordered dictionaries -- starting to feel more like a list. And I just saw a recipe for ordered sets. I can picture this going on and on ... what about unique lists, etc.

    Ok.

    在某种程度上,我同意你的看法。然而,数据结构库对于支持已经很好建立的数据结构的常见用例是有用的。这使得程序员不必浪费时间来尝试对标准结构进行自定义扩展。只要它不失控,而且我们仍然可以看到每个解决方案的独特效用,在架子上放一个轮子是很好的,所以我们不需要重新发明它。好的。

    一个很好的例子是counter()类。这本专门的词典对我来说已经用了好多次了(badoom tshhhhh!)它节省了我编写自定义解决方案的工作。我更愿意有一个社区帮助我开发和保持适当的Python最佳实践的解决方案,而不是我的自定义数据结构文件夹中的某个东西,一年只使用一到两次。好的。好啊。


    首先,在python 2中引入了有序字典和命名元组,但这并不是重点。

    我不会指给你看这些文件,因为如果你真的感兴趣的话,你已经读过了。

    集合类型之间的第一个区别是可变性。tuplefrozenset是不变的类型。这意味着它们可以比listset更有效。

    如果你想要一些东西,你可以随机或按顺序访问,但最终主要会改变,你需要一个list。如果你想要一些东西,你也可以在开始时改变,你需要一个deque

    你不能把你的蛋糕也吃了——你添加的每一个功能都会让你失去一些速度。

    dictsetlists和tuples `有根本不同。它们存储键的散列值,允许您快速查看其中是否有项,但需要键是可散列的。链接列表或数组的成员资格测试速度不同。

    当您访问OrderedDictNamedTuple时,您谈论的是在python中实现的内置类型的子类,而不是在c中实现的子类。它们用于特殊情况,就像您必须导入的标准库中的任何其他代码一样。它们不会把名称空间搞得乱七八糟,但当您需要它们时,它们是很好的。

    总有一天,你会编码,然后你会说,"伙计,现在我确切地知道他们所说的‘应该有一个——最好只有一个——显而易见的方法来做它’,set正是我需要的,我很高兴它是Python语言的一部分!如果我必须使用一个列表,那将是永久的。"那时你就会明白为什么会存在这些不同的类型。


    所有这些专门的收集类型都提供特定的功能,而列表、元组、dict和set的"标准"数据类型没有充分或有效地提供这些功能。

    例如,有时您需要一组唯一的项,并且您还需要保留遇到它们的顺序。您可以使用一个集合来跟踪成员身份,使用一个列表来跟踪顺序,但是您的解决方案可能会比专门为此目的设计的数据结构(如有序集合)更慢,也更需要内存。

    这些附加的数据类型(您在基本数据类型上将其视为组合或变化)实际上填补了基本数据类型所留下的功能空白。从实践的角度来看,如果Python的核心或标准库没有提供这些数据类型,那么任何需要它们的人都会发明自己的低效版本。它们的使用频率低于基本类型,但通常足以使其在提供标准实现的同时具有价值。


    字典是按键索引的(事实上,它是一个散列映射);元组的一般列表不会是。您可能会认为两者都应该作为关系来实现,可以随意添加索引,但是在实践中,为常见用例优化类型既方便又高效。

    添加新的专门化集合是因为它们非常常见,以至于很多人最终都会使用更基本的数据类型来实现它们,然后您会遇到车轮重新设计的常见问题(浪费精力、缺乏互操作性…)。如果Python只是提供了一个完全通用的构造,那么我们会有很多人问"我如何使用关系实现集合"等等。

    (顺便说一句,我使用的是数学或db意义上的关系)


    The Zen of Python says"There should be one-- and preferably only one --obvious way to do it". It seems to me this profusion of specialized collections types is in conflict with this Python precept.

    不是远程的。这里有几个不同的事情要做。我们为这项工作选择了合适的工具。所有这些容器都是根据几十年前经过试验、测试和真实的CS概念建模的。

    字典不像元组:它们是为键值查找而优化的。元组也是不可变的,它区别于一个列表(您可以把它看作是一个frozenlist)。如果您发现自己在将字典转换为列表和列表,那么几乎肯定是在做错事;举个例子会有所帮助。

    命名元组的存在是为了方便,实际上是为了替换简单的类而不是字典。有序字典只是有点包装,以记住添加到字典中的内容的顺序。在3.x中,这两种语言都不是新的(尽管可能有更好的语言支持,但我还没有找到)。


    数据结构(语言不可知论)的世界通常可以归结为一些小的基本结构——列表、树、哈希表和图等,以及它们的变体和组合。在使用和实现方面,每种方法都有其特定的用途。

    我不认为你可以在不指定字典的情况下,将字典简化为具有特定唯一性约束的元组列表。字典有一个特定的用途——键/值查找——数据结构的实现通常是根据这些需求而定制的。集合在许多方面与字典相似,但对集合的某些操作在字典上没有意义(联合、分离等)。

    我不认为这违背了"Python禅"的做事方式。虽然您可以使用已排序的字典来执行字典所做的操作,而不使用已排序的部分,但您更违反了Occam的Razor,可能会导致性能损失。我认为这与能够以不同的方式在语法上处理La Perl有所不同。


    在Python中,我最喜欢的是敏捷性。很多功能性的、有效的和可用的集合类型都给了我。

    还有一种方法可以做到这一点——每种类型都有自己的工作。