元组(tuple)有什么用处?

57

我现在正在上Python课,我们刚学习了元组这种数据类型。我阅读了维基百科关于它的页面,但是我无法弄清楚在实践中这种数据类型何时会有用处。能否给一些例子呢?也许是在Python中,需要一个不可变的数字集合。那这与列表的区别在哪里?

12个回答

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

2
从挑剔的编程语言专家的角度来看:Python 在这里混淆了多个概念;在静态类型语言中,“元组”类型匹配包含固定数量子值和固定类型的值。例如,(string * int) 是包含字符串和整数的元组类型。然而,在动态类型语言中,这种意义似乎被淹没了。不可变性的概念通常不与元组相关联;Python 似乎已经占用并重新定义了“元组”这个术语。 - John Clements
元组也由一些集合对象返回,例如enumerate(),其中了解元组是有用的。 - Murphy
这是我用来返回多个值的方法。 - Ridhwaan Shakeel

21

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

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

我主要使用这个功能创建一个键为网格顶点坐标的字典。然而,在我的特定情况下,所涉及的浮点数的精确比较正常工作,但这可能并不总是适用于您的目的(在这种情况下,我可能会将传入的浮点数转换为某种固定点整数)。


3
我从未考虑过将它们用作字典键。好主意。 - crystalattice

14

最好的理解方式是:

  • 元组是一个没有字段名称的记录
  • 当您不想指定字段名称时,可以使用元组代替记录。

因此,您可以避免编写以下内容:

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, Integer)元组的函数中返回一个(String, String)元组。您还不能在类型声明表示您计划返回元组时返回列表,反之亦然。列表严格用于增长项目集合,而元组严格用于固定大小的记录。如果您愿意,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很友好)。这些语言的设计者认为不变性非常有用,所以所有列表在那里都是不可变的。 (不是更改列表以添加或删除项目,而是使用添加或删除项目的新列表。不变性保证旧列表的副本永远不会更改,因此编译器和运行时可以通过在新列表中重用旧列表的部分并在不再需要时进行垃圾回收来使代码执行良好。)

我很感激这个答案。非常有启发性,上下文和例子真的帮助我巩固了我的理解。谢谢! - NaiveBae

10

我喜欢这个解释

基本上,当有一个常量结构时(第一个位置始终包含一种类型的值,第二个位置包含另一种类型的值等等),应该使用元组;而列表应该用于同类值的列表。

当然总有例外,但这是一个很好的通用指南。


5

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

因此,当您拥有不具有易变性质的列表,并且需要保证没有消费者对其进行更改时,您可以使用元组。

典型的例子是应用程序中的固定数据,例如公司部门、类别等。如果这些数据发生变化,通常只有一个生产者会重建元组。


2

元组是一系列的值,这些值可以是任何类型,并且它们由整数索引,所以元组不像列表。最重要的区别在于元组是不可变的

元组是由逗号分隔的值列表:

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

在IT技术中,将元组用括号括起来是一种良好的实践:

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

2

如果您需要将两个或更多对象作为一个集合处理,那么它们非常有用。


1

使用元组

  1. 如果您的数据不需要或者不会被更改。

  2. 元组比列表更快。如果我们正在定义一组常量值,并且我们将始终通过迭代来处理它,则应该使用元组而不是列表。

  3. 如果我们需要一个元素数组作为字典键,则可以使用元组。由于列表是可变的,因此永远不能用作字典键。

此外,元组是不可变的,而列表是可变的。同样地,元组的大小是固定的,而列表是动态的。

a_tuple = tuple(range(1000))
a_list = list(range(1000))
a_tuple.__sizeof__()  # 8024 bytes
a_list.__sizeof__()   # 9088 bytes

更多信息: https://jerrynsh.com/tuples-vs-lists-vs-sets-in-python/ 元组、列表和集合是Python中常用的数据结构。它们都有自己的优点和用途。元组是不可变的,可以用来存储不可更改的数据,如日期或坐标。列表是可变的,可以添加、删除、排序和修改其中的元素。集合是无序的,可以用来去重或交集操作。
在使用这些数据结构时需要注意它们的特性,选择合适的数据结构可以提高代码的效率和可读性。

1

就功能而言,列表总是可以替代元组(除了作为字典中的键)。但是,元组可以使事情更快。例如,在Java中使用不可变字符串时也是如此--您何时需要无法更改字符串?从来没有!

我刚刚阅读了一篇有关限制您所能做的内容以制作更好程序的讨论; 为什么函数式编程很重要


1

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接