什么是元组有用?

时间:2008-09-03 16:13:07

标签: python tuples

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

11 个答案:

答案 0 :(得分:52)

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

答案 1 :(得分:18)

当你需要将多个数据组合到你的密钥中时,元组会创建好的字典密钥,而不想为它创建一个类。

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

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

答案 2 :(得分:8)

我喜欢this explanation

基本上,当有一个常量结构时,你应该使用元组(第一个位置总是包含一种类型的值,第二个位置是另一个,依此类推),并且列表应该用于同类值列表。

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

答案 3 :(得分:3)

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

因此,如果您的列表本质上不是易变的,并且您需要保证没有消费者在改变它,那么您可以使用元组。

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

答案 4 :(得分:3)

最好的思考方式是:

  • 元组是record,其字段没有名称。
  • 当您不麻烦指定字段名称时,可以使用元组而不是记录。

所以不要像这样写东西:

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不同,大多数函数式编程语言都是静态类型的(变量只能保存一种类型的值,而该类型是在编译时确定的)。静态类型使元组的作用更加明显。例如,使用榆木语言:

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是最友好的语言)。这些语言的设计者认为不变性非常有用,以至于 all 列表在那里都是不变的。 (make a new list with the item added or removed不需要更改列表来添加或删除项目。不可变性保证了列表的旧副本永远不会改变,因此编译器和运行时可以通过重用部分代码来使代码性能良好新列表中的旧列表,并在需要时将剩余部分垃圾回收。)

答案 5 :(得分:2)

当你总是将两个或多个对象作为一个集处理时,我觉得它们很有用。

答案 6 :(得分:2)

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

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

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

最好将元组括在括号中:

float: right, display:block

答案 7 :(得分:1)

列表总是可以替换一个元组,就功能而言(显然,除了作为dict中的键)。但是,元组可以使事情变得更快。例如,Java中的不可变字符串也是如此 - 您何时需要无法更改字符串?从未!

我刚刚阅读了一篇关于限制你可以做些什么才能制作更好节目的讨论; Why Why Functional Programming Matters Matters

答案 8 :(得分:1)

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

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

答案 9 :(得分:0)

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

但是,我试着明白这个特殊用途。如果在整个代码中大量使用cookie,最好创建一个类,因为它有助于记录它们的使用。如果它们只在一个地方使用(例如一对方法),那么我可能会使用一个元组。在任何情况下,因为它是Python,你可以从元组开始,然后将其更改为自定义类的实例,而无需更改调用者中的任何代码。

答案 10 :(得分:0)

在以下位置使用了组合:

  1. 将元素序列保持不变的地方
  2. 在元组分配中
a,b=1,2
  1. 可变长度参数中
def add(*arg) #arg is a tuple
    return sum(arg)