谨慎执行 Python 序列的重复操作

作者: 潘峰 / 2020-12-24 / 分类: Work

Python

序列是 Python 内置类型之一,常见的字符串、元组、列表都是序列类型的子类型。
Python 中序列支持重复 (*) 操作,可以便捷地生成包含 n 个重复元素的序列对象。

示例如下:

>>> '你好' * 3
'你好你好你好'

>>> [1] * 3
[1, 1, 1]

>>> (1, 2) * 3
(1, 2, 1, 2, 1, 2)

>>> '1' * 0
''

但值得注意的是,重复操作实际上是在对元素进行浅拷贝操作,例如:

>>> a = ('abc',) * 2
>>> id(a[0])
4304340272
>>> id(a[1])
4304340272

当我们拷贝的元素是不可变对象时,不会有什么问题,但如果拷贝的元素是可变对象时,就会出现如下问题:

>>> a = ([1],) * 3
>>> a
([1], [1], [1])

>>> a[0].append(2)
>>> a
([1, 2], [1, 2], [1, 2])

>>> a[1].append(3)
>>> a
([1, 2, 3], [1, 2, 3], [1, 2, 3])

如果我们明白什么是浅拷贝,自然会知道发生了什么。
因此当我们需要对序列进行重复 (*) 操作时,要特别注意重复的元素尽量是不可变对象。如果我们需要创建一个包含多个相同的可变对象的序列时(比如动态规划创建 dp),建议使用列表生成器的方式:

>>> a = [[1] for _ in range(3)]
>>> a
[[1], [1], [1]]
>>> id(a[0])
4305451200
>>> id(a[1])
4305451328
>>> id(a[2])
4305451264