繁体   English   中英

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

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

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

但是我确实想知道为什么这些结构会被视为不同,以及随着时间的推移它会如何变化(变得陌生)。 回到Python 2.x,我可以提出一个论点,他们都只是基本集合类型的变体,并且有些令人恼火的是,一些非奇特的用例要求你将字典转换为列表并返回再次。 (字典不仅仅是具有特定唯一性约束的元组列表吗?列表不是仅具有不同类型的唯一性约束的集合吗?)。

现在在3.x世界中,它变得更加复杂。 现在有名为元组 - 开始感觉更像是一个特例字典。 现在有订单的词典 - 开始感觉更像是一个列表。 我刚看到有序套装的配方。 我可以想象一下这个......还有什么独特的清单等等。

Python的禅宗说“应该有一个 - 最好只有一个 - 明显的方式”。 在我看来,这种专门的集合类型的大量与这个Python规则相冲突。

硬核Pythonistas的想法是什么?

这些数据类型都有不同的用途,在理想的世界中,您可以更多地统一它们。 但是,在现实世界中,我们需要有效地实现基本集合,例如,排序会增加运行时惩罚。

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

你正在寻找的大统一实际上是以不同的访问协议(getitem,getattr,iter,...)的形式,这些类型混合和匹配用于它们的预期目的。

tl; dr(鸭子打字)

你在所有这些数据结构中看到一些相似之处是正确的。 请记住,python使用duck-typing (如果它看起来像鸭子和呱呱叫鸭子那么它就是鸭子)。 如果您可以在相同的情况下使用两个对象,那么对于您当前的意图和目的,它们可能也是相同的数据类型。 但是你总是要记住,如果你试图在其他情况下使用它们,它们可能不再以相同的方式运行。

考虑到这一点,我们应该看看你提到的四种数据类型的实际不同和相同之处,以便大致了解它们可以互换的情况。

可变性(你可以改变吗?)

您可以更改词典,列表和集。 如果不制作副本,则无法“更改”元组。

  • 可变: dictlistset

    永恒: tuple

Python string也是一种不可变类型。 为什么我们想要一些不可变对象? 我会从这个答案中解释一下:

  1. 不可变对象可以进行很多优化

  2. 在Python中,只有不可变的是可散列的(并且只有可散列的对象可以是集合的成员,或者是字典中的键)。

比较此属性,列表和元组看起来像“最接近”的两种数据类型。 在高级别,元组是列表的不可变“冻结帧”版本。 这使得列表对于随时间变化的数据集很有用(因为您不必复制列表来修改它),但是元组对于字典键(必须是不可变类型)这样的东西很有用。

订购(以及关于抽象数据类型的说明)

字典就像一个集合,没有固有的概念顺序。 这与有订单的列表和元组形成对比。 dict或set中的项目的顺序是从程序员中抽象出来的,这意味着如果元素A for k in mydata循环中的for k in mydata出现在B之前,则不应该(并且通常不能)依赖于A之前的A B一旦你开始改变mydata

  • 保留订单: listtuple

    非订单保留: dictset

从技术上讲,如果你连续两次迭代mydata它将是相同的顺序,但这是python机制的一个方便的特性,而不是set 抽象数据类型的一部分( 数据的数学定义)类型)。 列表和元组确实保证了顺序,特别是不可变的元组。

你在迭代时看到的东西(如果它像鸭子一样走路......)

  • 每个“元素”一个“项目”: setlisttuple

    每个“元素”有两个“项目”: dict

我想在这里你可以看到一个命名元组,它具有每个元素的名称和值,作为字典的不可变模拟。 但这是一个微妙的比较 - 请记住,如果您尝试在命名元组上使用仅字典方法,则鸭子类型将导致问题,反之亦然。

直接回答您的问题

字典不仅仅是具有特定唯一性约束的元组列表吗?

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

此外,字典具有每个“元素”的键和值。 另一方面,元组可以具有任意数量的元素,但每个元素仅具有值。

由于字典的机制,键的作用就像一个集合,如果你有密钥,你可以在恒定的时间内查找值。 在元组列表(这里是对)中,您需要遍历列表直到找到密钥,这意味着搜索将与列表中的元素数量成线性关系。

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

列表不是仅具有不同类型的唯一性约束的集合吗?

我再次强调,集合没有固有的顺序,而列表则没有。 这使列表更有用于表示堆栈和队列之类的内容,您希望能够记住附加项目的顺序。 套装没有这样的保证。 然而,它们确实提供了能够在恒定时间内进行成员资格查找的优势,而再次列表需要线性时间。

现在有名为元组 - 开始感觉更像是一个特例字典。 现在有订单的词典 - 开始感觉更像是一个列表。 我刚看到有序套装的配方。 我可以想象一下这个......还有什么独特的清单等等。

在某种程度上,我同意你的意见。 但是,数据结构库可用于支持已经完善的数据结构的常见用例。 这使程序员不必浪费时间尝试为标准结构提供自定义扩展。 只要它不会失控,我们仍然可以看到每个解决方案中的独特用途,最好在货架上安装一个轮子,这样我们就不需要重新发明它了。

一个很好的例子是Counter()类。 这个专业词典对我来说比我可以使用的次数多了很多次(badoom-tshhhhh!),它为我节省了编写自定义解决方案的工作量。 我宁愿有一个解决方案,社区正在帮助我开发和保持适当的python最佳实践,而不是在我的自定义数据结构文件夹中的东西,并且每年只使用一次或两次。

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

我不会指出你的文档,因为如果你真的感兴趣,你会读它们。

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

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

你根本无法拥有自己的蛋糕而且吃得太多 - 你添加的每个功能都会让你失去一些速度。

dictsetlists和元set有根本的不同。 它们存储密钥的哈希值,允许您快速查看项目是否在其中,但需要密钥可以清除。 您没有使用链接列表或数组获得相同的成员资格测试速度。

当你到达OrderedDictNamedTuple ,你谈论的是用Python实现的内置类型的子类,而不是C语言。它们用于特殊情况,就像你必须导入的标准库中的任何其他代码一样。 它们不会使命名空间变得混乱,但是当你需要它们时很高兴。

有一天,你会编码,你会说,“男人,现在我确切地知道他们的意思是'应该有一个 - 最好只有一个 - 明显的方式去做', set 正是我需要什么,这一点,我很高兴它是Python语言的一部分!如果让我用一个列表,它会永远需要“。 那时你会明白为什么存在这些不同的类型。

字典按键索引(事实上,它是一个哈希映射); 一个通用的元组列表将不会。 您可能会认为两者都应该作为关系实现,并且能够随意添加索引,但实际上,为常见用例提供优化类型更方便,更有效。

新的专业集合被添加,因为它们很常见,很多人最终会使用更基本的数据类型来实现它们,然后你就会遇到轮子改造的常见问题(浪费精力,缺乏互操作性......)。 如果Python只提供了一个完全通用的构造,那么我们会让很多人问“如何使用关系实现集合”等。

(顺便说一句,我在数学或数据库意义上使用关系)

所有这些专门的集合类型都提供了由list,tuple,dict和set的“标准”数据类型无法充分或有效提供的特定功能。

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

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

我最喜欢Python中的一件事就是敏捷性。 许多功能,有效和可用的集合类型给了我。

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

数据结构的世界(语言不可知)通常可以归结为一些小的基本结构 - 列表,树,散列表和图形等,以及它们的变体和组合。 每个在使用和实施方面都有自己的特定目的。

我不认为您可以执行诸如将字典缩减为具有特定唯一性约束的元组列表而不实际指定字典的操作。 字典具有特定目的 - 键/值查找 - 并且数据结构的实现通常是针对这些需求而定制的。 集合在很多方面都像字典,但集合上的某些操作在字典(union,disjunction等)上没有意义。

我没有看到这违反了“禅宗之谜”的做法。 虽然您可以使用排序字典来执行字典所执行的操作而不使用已排序的部分,但您更多地违反了Occam的剃刀并且可能会导致性能下降。 我认为这不同于能够在语法上以不同的方式做一些Perl。

Python的禅宗说“应该有一个 - 最好只有一个 - 明显的方式”。 在我看来,这种专门的集合类型的大量与这个Python规则相冲突。

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

字典与元组不同:它们针对键值查找进行了优化。 元组也是不可变的,它将它与列表区分开来(您可以将其视为类似于frozenlist )。 如果您发现自己将字典转换为列表并返回,那么您几乎肯定会做错事; 一个例子会有所帮助。

为方便起见,存在命名元组,实际上是用于替换简单类而不是字典。 有序词典只是为了记住事物被添加到字典中的顺序。 并且在3.x中都不是新的(虽然可能有更好的语言支持他们;我没看过)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM