Python元组:不变性的神话

list之外元组是Python中最常用的一些集合。主要有两个基本用例: 

  • 作为记录。

  • 作为不可变的列表。 

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

元组作为记录

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

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

t_movie_1 =(“教父”,1972年,“弗朗西斯·福特·科波拉”)
#元组记录形式的电影详细信息(标题,制作年份,导演)
标题,年份,导演 = t_movie_1
#元组拆包
t_movie_2 =(“低俗小说”,1994,“昆汀·塔伦蒂诺”)
list_movies =(t_movie_1,t_movie_2)
#元组电影记录列表
对于 list_movies中的movie_title,movie_year  , movie_director:
    打印(movie_title)
#教父
#低俗小说
我是一名python开发工程师,整理了一套python的学习资料,从基础的python脚本到web开发、爬虫、
数据分析、数据可视化、机器学习、面试真题等。想要的可以进群:688244617免费领取

 在上一个代码块中,请注意第三行:元组拆包会影响元组的项,从而仅通过一个表达式将它们分隔在不同的变量上。

这种机制(拆包)可以与每个可迭代对象一起使用,而不仅限于元组。要注意的主要点是,除非* 用于捕获列表中的其他项,否则元组中的项数必须与表达式左侧部分中的变量数相同  。

下面的代码块显示了对* unpacking元组的使用  。

t_movie_1 =(“教父”,1972年,“弗朗西斯·福特·科波拉”)
#元组记录形式的电影详细信息(标题,年份,导演)
标题,年份,导演 = t_movie_1
打印(“%s,%s,%s”  %(职称,年份,导演))
#教父,1972年,弗朗西斯·福特·科波拉
标题,* rest = t_movie_1
打印(标题,其余)
#教父,[1972年,弗朗西斯·福特·科波拉(Francis Ford Coppola)]


在某些情况下,仅通过其位置来解释记录(元组)中的字段含义不是很容易理解和实用。这就是python标准库中的package集合提供namedtuple对象的原因。该collections.namedtuple是一个工厂函数创建的元组的字段名和类名的子类。

从 集合中 导入 namedtuple
 
电影 = namedtuple(“电影”,““标题”,“年份”,“导演” ])
#creationnamedtuple子类,将Movie作为类的名称并列出 
#fileds
m1 = 电影(“教父”,1972年,“弗朗西斯·福特·科波拉”)
#命名元组m1的实例化
列印(m1)
#电影(title ='教父',year = 1972,导演='Francis Ford Coppola')
打印(M1。标题)
#教父


许多人更喜欢将字典用作数据记录容器而不是元组。尽管字典在此范围内是完整的,但与元组甚至与namedtuple相比,它们消耗太多的内存。

元组称为“不可变列表”

Pyhton的许多入门教程都提到元组是不可变的列表。没错,但也不是100%准确。

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

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

t_movie_1 =(“教父”,1972年,“弗朗西斯·福特·科波拉”)
#元组记录形式的电影详细信息(标题,年份,导演)
t_movie_2 =([[ 教父],“教区”,1972年,“弗朗西斯·福特·科波拉”)
#same movie tuple,但具有一个列表,其中包含以不同语言显示的电影名称
t_movie_1 [ 0 ] = “ le parrain”
#TypeError:“元组”对象不支持项目分配
t_movie_2 [ 0 ]。附加(“ el padrino”)
打印(t_movie_2)
#([['教父','le parrain','el padrino'],1972,'Francis Ford Coppola')


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

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

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

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

t_movie_2 =([[ 教父],“教区”,1972年,“弗朗西斯·福特·科波拉”)
#same movie tuple,但具有一个列表,其中包含以不同语言显示的电影名称
打印(id(t_movie_2 [ 0 ]))
#2704848
t_movie_2 [ 0 ]。附加(“ el padrino”)
打印(t_movie_2)
#([['教父','le parrain','el padrino'],1972,'Francis Ford Coppola')
打印(id(t_movie_2 [ 0 ]))
#2704848


在上一个代码块中,在append 方法调用后,元组中的列表对象(排序中的引用)的id不变  。

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

如果您尝试影响新列表而不是元组中的旧列表,  TypeError 则会引发a,因为这种影响包括用新列表中的新列表替换现有列表引用,使其具有与可变对象相同的行为。 。

t_movie_2 =([[ 教父],“教区”,1972年,“弗朗西斯·福特·科波拉”)
t_movie_2 [ 0 ] = [ '教父','le parrain','el padrino' ]
#TypeError:“元组”对象不支持项目分配


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

+= 在元组中的可变容器上使用运算符时,会发生一种非常典型的情况  。让我们通过以下示例进行探索:

t_movie_2 =([[ 教父],“教区”,1972年,“弗朗西斯·福特·科波拉”)
t_movie_2 [ 0 ] + = 'el padrino'
#TypeError:“元组”对象不支持项目分配


该  += 运营商提出了一个  TypeError。您可以说这是正常现象,我也同意您的观点-毕竟  += 是一个类似于该= 运算符的赋值运算  符,所以为什么要期待与此行为不同的另一种行为! 

真正令人震惊的是,即使提出了例外,也确实发生了情感。请参阅下面的代码。

t_movie_2 =([[ 教父],“教区”,1972年,“弗朗西斯·福特·科波拉”)
尝试:
    t_movie_2 [ 0 ] + = [ 'el padrino' ]
除了 TypeError  如 ex:
    打印(str(ex))
#'tuple'对象不支持项目分配
打印(t_movie_2)
#([['教父','le parrain','el padrino'],1972,'Francis Ford Coppola')


尽管可以解释,但这很奇怪。这  += 不是基本操作;如果检查此操作的汇编代码,您将意识到,首先添加了列表,然后引发了异常,因此即使有异常,附加操作也已完成。

结论 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值