Logo
Section 1 / 6

Python中的可变性

了解不同的可变和不可变数据类型。

导入

Python中的可变性

了解不同的可变和不可变数据类型。

我们称一个对象为可变的(mutable),如果它在创建后其值可以被更改。一个对象是不可变的(immutable),如果它的值在创建时就固定下来,且永远无法改变。不可变的值本质上是只读的。在本章中,我们将探讨 Python 中的可变性,以及两类对象各自的优缺点。

可变性

在 Python 中,通常对象的类型决定了它是可变还是不可变。例如,列表是可变的。当你创建一个列表后,可以通过多种方式对其进行修改,如下所示:

1k = [10, 20, 30] 2k[1] = 7 # k 现在是 [10, 7, 30] 3print(k) 4k.append(5) # k 现在是 [10, 7, 30, 5] 5print(k) 6del k[2] # k 现在是 [10, 7, 5] 7print(k)

还有许多其他方式可以修改列表,但这里不再一一列举,因为这些操作在 Python 中非常常见。

元组与列表几乎完全相似,唯一的区别在于它们是不可变的。一旦创建了元组,就无法以任何方式更改它。你不能添加或删除元素,也不能用其他值替换某个元素。如果你尝试对元组执行上述代码,会发生以下情况:

1t = (10, 20, 30) 2t[1] = 7 # TypeError: 元组不支持赋值 3t.append(5) # AttributeError: 元组没有 append 方法 4del t[2] # TypeError: 元组不支持删除

你根本无法对元组执行任何可变操作。所有可用于修改列表的操作在元组上都不可用,因此元组一旦创建就永远无法改变。

需要注意的一点是:变量本身并不是对象——变量仅持有对对象的引用。因此,以下操作是完全合法的:

1t = (10, 20, 30) 2print(t) 3t = (3, 2, 1) 4print(t)

第一行之后,t 引用了元组 (10, 20, 30)。第二行之后,t 引用了新的元组 (3, 2, 1)。

但是,我们并没有改变原有元组的值。我们只是创建了一个具有新值的新元组,并将变量 t 重新指向这个新元组。原来的元组仍然存在且未被修改,但由于没有任何引用指向它,它最终会被垃圾回收。

除了列表和元组之外,还有其他几种可变的数据类型,包括字典和集合。同时,也存在多种不可变的数据类型,包括字符串、冻结集合(set 的不可变版本)以及数字类型。

可变数据类型不可变数据类型
list, set, dictionarytuple, string, frozenset, int, float, complex

数字是不可变的

顺便提一下,你可能会惊讶地发现数字在 Python 中是不可变的。这是因为数字在 Python 中也是对象,如果它们是可变的,将会导致一些非常奇怪的行为。想象下面这段代码:

1a = 3 2b = a 3a = 4 4 5print(a, b)

第一行创建了一个值为 3 的 int 对象,并将其赋给变量 a(变量 a 引用了这个 int 对象)。第二行将 a 赋给 b,因此变量 b 也引用了同一个 int 对象。

现在,第三行将 a 设置为 4。如果这个操作真的改变了 int 对象的值,那么不仅 a 会等于 4,b 也会等于 4!这显然会造成严重问题。幸运的是,数字是不可变的,因此第三行实际上创建了一个新的 int 对象,值为 4,并将其赋给 a。变量 b 仍然指向原始的 int 对象,其值仍为 3。

闭包

可变对象的问题:意外修改