我现在正在学习 Python 课程,我们刚刚介绍了元组作为数据类型之一。我阅读了它的维基百科页面,但是,我无法弄清楚这种数据类型在实践中会有什么用处。我可以提供一些需要一组不可变数字的示例吗?也许是在 Python 中?这与列表有何不同?

有帮助吗?

解决方案

  • 每当您想要从函数返回多个结果时,就可以使用元组。
  • 由于它们是不可变的,因此可以用作字典的键(列表不能)。

其他提示

当您需要将多个数据组合到键中并且不想为其创建一个类时,元组可以成为很好的字典键。

a = {}
a[(1,2,"bob")] = "hello!"
a[("Hello","en-US")] = "Hi There!"

我主要使用此功能来创建一个字典,其中的键是网格顶点的坐标。然而,在我的特定情况下,所涉及的浮点数的精确比较工作得很好,但这可能并不总是适合您的目的[在这种情况下,我可能会将您传入的浮点数转换为某种定点整数]

我喜欢 这个解释.

基本上,当存在常量结构时,您应该使用元组(第一个位置始终保存一种类型的值,第二个位置始终保存另一种类型,依此类推),并且列表应该用于同类值的列表。

当然总有例外,但这是一个很好的一般准则。

元组和列表通常具有相同的用途。一般来说,不可变数据类型有很多好处,主要是关于并发问题。

因此,当您的列表本质上不是易失性的并且您需要保证没有消费者改变它时,您可以使用元组。

典型示例是应用程序中的固定数据,例如公司部门、类别等。如果此数据发生变化,通常由单个生产者重建元组。

最好的思考方式是:

  • 元组是一个 记录 其字段没有名称。
  • 当您懒得指定字段名称时,可以使用元组而不是记录。

所以不要写这样的东西:

person = {"name": "Sam", "age": 42}
name, age = person["name"], person["age"]

或者更详细:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("Sam", 42)
name, age = person.name, person.age

你可以这样写:

person = ("Sam", 42)
name, age = person

当您想要传递只有几个字段的记录或仅在少数地方使用的记录时,这非常有用。在这种情况下,使用字段名称指定全新的记录类型(在 Python 中,您将使用对象或字典,如上所述)可能会过于冗长。

元组起源于函数式编程的世界 (Haskell、OCaml、Elm、F# 等),它们通常用于此目的。与 Python 不同,大多数函数式编程语言都是静态类型的(变量只能保存一种类型的值,并且该类型在编译时确定)。静态类型使元组的作用更加明显。例如,在 Elm 语言中:

type alias Person = (String, Int)

person : Person
person = ("Sam", 42)

这强调了这样一个事实:特定类型的元组始终应该具有固定顺序的固定数量的字段,并且每个字段始终应该具有相同的类型。在此示例中,一个人始终是两个字段的元组,一个是字符串,另一个是整数。

上面与列表形成鲜明对比, ,它们应该是可变长度的(每个列表中的项目数量通常不同,并且您编写函数来添加和删除项目)并且列表中的每个项目通常具有相同的类型。例如,您有一个人员列表和另一个地址列表 - 您不会在同一列表中混合人员和地址。而在同一个元组中混合不同类型的数据则是元组的全部意义所在。元组中的字段通常具有不同类型(但并非总是如此 - 例如你可以有一个 (Float, Float, Float) 表示 x,y,z 坐标的元组)。

元组和列表通常是嵌套的。 有一个元组列表是很常见的。您可以拥有 Person 元组列表以及 Person 对象列表。您还可以有一个值为列表的元组字段。例如,如果您有一个地址簿,其中一个人可以有多个地址,那么您可以有一个类型的元组 (Person, [String]). 。这 [String] 类型通常在函数式编程语言中用于表示字符串列表。在 Python 中,您不会写下类型,但您可以以完全相同的方式使用这样的元组,将 Person 元组的第一个字段中的对象和第二个字段中的字符串列表。

在Python中,会出现混乱 因为语言不 执行 编译器在静态类型函数语言中强制执行的任何这些实践。在这些语言中,您不能混合不同类型的元组。例如,您不能返回 (String, String) 来自函数的元组,其类型表明它返回一个 (String, Integer) 元组。当类型表明您计划返回元组时,您也无法返回列表,反之亦然。列表严格用于不断增长的项目集合,而元组严格用于固定大小的记录。如果您愿意,Python 不会阻止您违反任何这些规则。

在 Python 中,列表有时会转换为元组以用作字典键,因为 Python 字典键需要是不可变的(即常量)值,而 Python 列表是可变的(您可以随时添加和删除项目)。这是针对 Python 中特定限制的解决方法,而不是作为计算机科学概念的元组的属性。

所以在Python中,列表是可变的,而元组是不可变的。但这只是一种设计选择,而不是计算机科学中列表和元组的固有属性。您也可以拥有不可变列表和可变元组。

在 Python 中(使用默认的 CPython 实现),在大多数情况下,元组也比对象或字典更快,因此偶尔会出于这个原因使用元组,即使使用对象或字典命名字段会更清晰。

最后,为了更明显地表明元组是另一种记录(而不是另一种列表),Python 还具有 命名元组:

from collections import namedtuple

Person = namedtuple("Person", "name age")

person = Person("Sam", 42)
name, age = person.name, person.age

这通常是最好的选择 - 比定义新类更短,但字段的含义比使用字段没有名称的普通元组更明显。

不可变列表对于许多用途都非常有用, ,但这个话题太复杂了,无法在这里回答。主要的一点是,无法改变的事情比可以改变的事情更容易推理。大多数软件错误都是由于事物以意想不到的方式发生变化而产生的,因此限制它们可以改变的方式是消除错误的好方法。如果您有兴趣,我建议您阅读有关函数式编程语言的教程,例如 Elm、Haskell 或 Clojure(Elm 是最友好的)。这些语言的设计者认为不变性非常有用,以至于 全部 那里的列表是不可变的。(您无需更改列表来添加和/或删除项目,而是 创建一个新列表,其中添加或删除了项目. 。不变性保证了列表的旧副本永远不会改变,因此编译器和运行时可以通过在新列表中重新使用旧列表的部分内容并在剩余部分更长时对剩余部分进行垃圾收集来使代码执行良好需要。)

当您总是将两个或多个对象作为一组处理时,我发现它们很有用。

元组是值的序列。值可以是任何类型,并且它们按整数索引,因此元组不像列表。最重要的区别是 元组是不可变的。

元组是一个以逗号分隔的值列表:

t = 'p', 'q', 'r', 's', 't'

将元组括在括号中是一种很好的做法:

t = ('p', 'q', 'r', 's', 't') 

就功能而言,列表总是可以替换元组(显然,作为字典中的键除外)。然而,元组可以让事情进展得更快。对于 Java 中的不可变字符串来说也是如此——什么时候您需要无法更改字符串?绝不!

我刚刚读了一篇关于限制你可以做什么以制作更好的程序的不错的讨论; 为什么函数式编程很重要

元组对于存储多个值很有用。正如您所注意到的,元组就像一个不可变的列表 - 例如一旦创建,您就无法添加/删除/交换元素。

不可变的好处之一是,由于元组的大小是固定的,因此它允许运行时执行某些优化。当在函数的返回值或参数的上下文中使用元组时,这特别有用。

除了语法上需要它们的地方(例如字符串 % 操作和多个返回值)之外,我还使用元组作为轻量级类的形式。例如,假设您有一个对象,它从一个方法向调用者传递一个不透明的 cookie,然后将其传递到另一个方法。元组是将多个值打包到 cookie 中的好方法,而无需定义单独的类来包含它们。

不过,我会尽量谨慎对待这种特殊用途。如果在整个代码中大量使用cookie,最好创建一个类,因为它有助于记录它们的使用。如果它们仅在一个地方使用(例如一对方法)那么我可能会使用一个元组。无论如何,因为它是 Python,所以您可以从一个元组开始,然后将其更改为自定义类的实例,而无需更改调用方中的任何代码。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top