baby-python-on-forest-floor

斯利思里·博伊

列表一起,元组是Python中使用的一些最常见的集合。它们主要有两个基本用例:

  • 作为记录。

  • 作为不可变列表。

下面,我们将讨论两者的功能,并着重讨论元在实际应用中的不变性。

您可能还喜欢:Python 中的映射和筛选函数。

元数作为记录

作为记录,元数保存数据,其每个项表示一个字段。在这种情况下,项目的顺序非常重要,因为元组中的每个位置都表示特定字段。

字段的表示取决于其位置。由于位置很重要,因此用作数据记录的元数的大小必须固定和知道,以及每个项目的重要性。

t_movie_1 = ('The Godfather', 1972, " Francis Ford Coppola")
# Tuple as a record of movie details of form (title, year of production, director)
title, year, director = t_movie_1
# tuple unpacking
t_movie_2 = ('Pulp fiction', 1994, " Quentin Tarantino")
list_movies = (t_movie_1, t_movie_2)
#a list of tuple movie records
for movie_title, movie_year, movie_director in list_movies:
    print(movie_title)
#The Godfather
#Pulp fiction

在前面的代码块中,注释行三:元组解压缩会影响元组的项目,以便仅在一个表达式中将它们分隔在不同的变量上。

此机制(解压缩)可用于每个可迭代对象,而不仅仅是元数。需要尊重的要点是,元组中的项数必须与表达式左侧的变量数相同,除非您使用 * 来捕获列表中的其他项。

下面的代码块显示了 * 使用 解包元组。

t_movie_1 = ('The Godfather', 1972, "Francis Ford Coppola")
# Tuple as a record of movie details of form (title, year, director)
title, year, director = t_movie_1
print ("%s, %s, %s" %(title, year, director))
#The Godfather, 1972, Francis Ford Coppola
title, *rest = t_movie_1
print (title, rest)
#The Godfather , [1972, 'Francis Ford Coppola']

在某些情况下,仅根据记录(元组)的位置来解释字段符号不是非常可读和实用的。这就是为什么 python 标准库中的包集合提供命名图普尔对象的原因。集合.nametuple是一个工厂函数,它创建具有字段名称和类名称的元组子类。

from collections import namedtuple

Movie = namedtuple("Movie", ["title", "year", "director"])
#creation of the namedtuple subclass with Movie as the name of the class and a list of 
#fileds
m1 = Movie('The Godfather', 1972, " Francis Ford Coppola")
#instanciation of the named tuple m1
print (m1)
#Movie(title='The Godfather', year=1972, director=' Francis Ford Coppola')
print(m1.title)
#The Godfather

许多人更喜欢将字典用作数据记录容器,而不是元数。虽然字典在此范围内是全手的,但它们消耗了太多的内存,与元组相比,甚至与命名图普尔这没有错,但它也不是100%准确。

在探索这些容器时,您可能会惊讶地发现,不可变的元数在某些情况下是可变的。

让我们直接从一个例子开始:

t_movie_1 = ('The Godfather', 1972, "Francis Ford Coppola")
# Tuple as a record of movie details of form (title, year, director)
t_movie_2 = (['The Godfather', 'le parrain'], 1972, "Francis Ford Coppola")
#same movie tuple but with a list that contains the name of the movie in different lanquages
t_movie_1[0] = "le parrain"
#TypeError: 'tuple' object does not support item assignment
t_movie_2[0].append("el padrino")
print(t_movie_2)
#(['The Godfather', 'le parrain', 'el padrino'], 1972, 'Francis Ford Coppola')

t_movie_1 一个元组是一个元组,只有不可变对象作为项(int、str、..),因为根据定义,元组是不可变的。尝试影响第一个项的另一个值会引发 TypeError exception

但是,请注意第二个元组行为。将新值追加到第一个项效果良好,新值将添加到元组中的 t_movie_2 列表中。

的第 t_movie_2 一项是可变列表。为什么没有引发 TypeError 异常?

那么,元组包含对列表的引用,而不是列表本身的项目。列表方法 append 不会更改该引用,但它会向列表中添加新项。因此,元组项(对列表的引用)并没有真正更改。

t_movie_2 = (['The Godfather', 'le parrain'], 1972, "Francis Ford Coppola")
#same movie tuple but with a list that contains the name of the movie in different lanquages
print( id(t_movie_2[0]))
#2704848
t_movie_2[0].append("el padrino")
print(t_movie_2)
#(['The Godfather', 'le parrain', 'el padrino'], 1972, 'Francis Ford Coppola')
print( id(t_movie_2[0]))
#2704848

在前面的代码块中,元组内列表对象的 ID(排序中的引用)在 append 方法调用后没有更改。

从技术上讲,元组没有改变(它真的是不可变的)。这是其可变列表的内容确实发生了变化。

如果尝试影响新列表以代替元组内的旧列表, TypeError 则将引发 ,因为影响包括将现有列表引用替换为新列表,以具有与可变对象相同的行为。

t_movie_2 = (['The Godfather', 'le parrain'], 1972, "Francis Ford Coppola")
t_movie_2[0] = ['The Godfather', 'le parrain', 'el padrino']
#TypeError: 'tuple' object does not support item assignment

下图描述了将新项目追加到元组列表中时发生的情况。

tuple immutability当您 += 在元组内的可变容器上使用运算符时,会出现一种非常典型的情况。让我们通过下面的示例来探讨它:

t_movie_2 = (['The Godfather', 'le parrain'], 1972, "Francis Ford Coppola")
t_movie_2[0] += 'el padrino'
#TypeError: 'tuple' object does not support item assignment

+=操作员提出 TypeError 。你可以说这是正常的,我同意你 – 毕竟 += 是一个分配运算符类似于 = 运算符,所以为什么期待不同的行为不同于这一个!

真正令人振奋的是,即使例外提出,影响也确实发生了;请参阅下面的代码+=不是基本操作;如果检查此操作的汇编器代码,您就会意识到,首先附加列表,稍后引发异常,因此,即使有例外,追加也已完成。

结论

总之,元数是非常容易使用和非常有用的。它们主要用作数据记录或不可变列表。元数的不变性取决于其中的项目类型。概括,元组是不可变的。但是,其中可变项不是。

相关文章

Comments are closed.