为什么元组可以包含可变项?

2025-02-18 09:24:00
admin
原创
106
摘要:问题描述:如果元组是不可变的,那么为什么它可以包含可变项?当可变项(例如列表)被修改时,它所属的元组仍然保持不变,这似乎是一个矛盾。解决方案 1:这是一个非常好的问题。关键的见解是,元组无法知道其中的对象是否可变。使对象可变的唯一方法是拥有改变其数据的方法。一般来说,没有办法检测这一点。另一个见解是,Pyth...

问题描述:

如果元组是不可变的,那么为什么它可以包含可变项?

当可变项(例如列表)被修改时,它所属的元组仍然保持不变,这似乎是一个矛盾。


解决方案 1:

这是一个非常好的问题。

关键的见解是,元组无法知道其中的对象是否可变。使对象可变的唯一方法是拥有改变其数据的方法。一般来说,没有办法检测这一点。

另一个见解是,Python 的容器实际上不包含任何东西。相反,它们保留对其他对象的引用。同样,Python 的变量不像编译语言中的变量;相反,变量名只是命名空间字典中的键,它们与相应的对象相关联。Ned Batchhelder 在他的博客文章中很好地解释了这一点。无论哪种方式,对象只知道它们的引用计数;它们不知道这些引用是什么(变量、容器或 Python 内部)。

这两个见解合在一起解释了您的谜团(为什么当底层列表发生变化时,“包含”列表的不可变元组似乎会发生变化)。事实上,元组并没有改变(它仍然具有与以前相同的对其他对象的引用)。元组无法改变(因为它没有变异方法)。当列表发生变化时,元组没有收到有关更改的通知(列表不知道它是被变量、元组还是另一个列表引用)。

在我们讨论这个话题时,这里还有一些其他的想法,可以帮助您完善关于元组是什么、它们如何工作以及它们的预期用途的心理模型:

  1. 元组的特点不是它们的不变性,而是它们的预期用途。

元组是 Python 将异构信息收集到一个屋檐下的方式。例如,
s = ('www.python.org', 80)
将一个字符串和一个数字组合在一起,以便主机/端口对可以作为套接字(复合对象)传递。从这个角度来看,拥有可变组件是完全合理的。

  1. 不变性与另一个属性哈希性密切相关。但哈希性不是绝对属性。如果元组的某个组件不可哈希,则整个元组也不可哈希。例如,t = ('red', [10, 20, 30])不可哈希。

最后一个例子展示了一个包含字符串和列表的 2 元组。元组本身不可变(即它没有任何用于更改其内容的方法)。同样,字符串是不可变的,因为字符串没有任何可变方法。列表对象确实有可变方法,因此可以更改。这表明可变性是对象类型的属性——有些对象有可变方法,有些没有。这不会因为对象嵌套而改变。

记住两点。首先,不变性不是魔法——它只是缺少变异方法。其次,对象不知道哪些变量或容器引用了它们——它们只知道引用计数。

希望这对你有用:-)

解决方案 2:

这是因为元组不包含列表、字符串或数字。它们包含对其他对象的引用。1无法更改元组包含的引用顺序并不意味着您不能改变与这些引用关联的对象。2

1.对象、值和类型(参见:倒数第二段)

2.标准类型层次结构(参见:“不可变序列”)

解决方案 3:

据我理解,这个问题需要重新表述为一个关于设计决策的问题:为什么 Python 的设计者选择创建一个可以包含可变对象的不可变序列类型?

要回答这个问题,我们必须考虑元组的用途:它们充当快速通用的序列。考虑到这一点,很明显为什么元组是不​​可变的,但可以包含可变对象。即:

  1. 元组速度且内存效率高:元组的创建速度比列表快,因为它们是不可变的。不可变性意味着可以使用常量折叠将元组创建为常量并按常量加载。这还意味着它们的创建速度更快,内存效率更高,因为不需要过度分配等。它们在随机访问项目方面比列表慢一点,但在解包方面又快了一点(至少在我的计算机上)。如果元组是可变的,那么它们在这些用途上就不会那么快了。

  2. 元组是通用的:元组需要能够包含任何类型的对象。它们用于(快速)执行诸如可变长度参数列表之类的操作(通过*函数定义中的运算符)。如果元组无法容纳可变对象,那么它们对于此类操作就毫无用处。Python 必须使用列表,这可能会减慢速度,并且内存效率肯定会降低。

所以你看,为了实现其目的,元组必须是不可变的,但也必须能够包含可变对象。如果 Python 的设计者想要创建一个不可变对象,并保证它“包含”的所有对象也是不可变的,他们就必须创建第三种序列类型。这种收益不值得额外的复杂性。

解决方案 4:

首先,“不可变”一词对不同的人来说可能意味着许多不同的东西。我特别喜欢 Eric Lippert 在他的博客文章[存档 2012-03-12 ] 中对不可变性的分类。在那里,他列出了以下几种不可变性:

  • 现实与真实的不变性

  • 一次写入不变性

  • 冰棒不变性

  • 浅层不变性与深层不变性

  • 不可变外观

  • 观察不变性

这些可以以各种方式组合起来,以形成更多种类的不变性,我相信还会有更多种类的不变性。你感兴趣的不变性类型似乎是深度不变性(也称为传递性不变性),其中不可变对象只能包含其他不可变对象。

关键在于,深度不变性只是众多不变性中的一种。你可以采用你喜欢的任何一种,只要你知道你对“不变”的概念可能与别人对“不变”的概念不同。

解决方案 5:

您无法更改id其项目。因此它将始终包含相同的项目。

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368

解决方案 6:

我在这里冒昧地说,这里相关的部分是,虽然你可以更改元组中列表的内容或对象的状态,但你无法更改对象或列表的存在。如果你有依赖于 thing[3] 是列表的东西,即使是空的,那么我认为这很有用。

解决方案 7:

一个原因是 Python 中没有通用的方法将可变类型转换为不可变类型(请参阅被拒绝的PEP 351以及链接的讨论以了解被拒绝的原因)。因此,如果有此限制,就不可能将各种类型的对象放入元组中,包括几乎任何用户创建的不可哈希对象。

字典和集合有此限制的唯一原因是它们要求对象可哈希,因为它们在内部实现为哈希表。但请注意,讽刺的是,字典和集合本身并不是不可变的(或可哈希的)。元组不使用对象的哈希,因此其可变性无关紧要。

解决方案 8:

元组是不可变的,因为元组本身不能扩展或缩小,而不是其本身包含的所有项都是不可变的。否则元组就很无趣了。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3970  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2740  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   79  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   87  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   74  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用