Python 列表切片语法用于没有明显理由的情况

38 投票
5 回答
12370 浏览
提问于 2025-04-11 19:19

我偶尔在Python代码中看到这样的列表切片语法:

newList = oldList[:]

这不就是和下面这个一样吗:

newList = oldList

还是说我有什么没理解的地方?

5 个回答

12

之前已经有人回答过这个问题了,我就简单演示一下:

>>> a = [1, 2, 3, 4]
>>> b = a
>>> c = a[:]
>>> b[2] = 10
>>> c[3] = 20
>>> a
[1, 2, 10, 4]
>>> b
[1, 2, 10, 4]
>>> c
[1, 2, 3, 20]
53

[:] 是用来创建一个“浅拷贝”的方法,这种拷贝会复制列表的结构,但里面的内容还是指向原始列表的成员。这意味着对这个拷贝进行的操作不会影响原始列表的结构。不过,如果你对列表中的成员做了什么修改,两个列表仍然会指向这些成员,所以通过原始列表访问时,修改的内容会显示出来。

而“深拷贝”则会把列表中的所有成员都复制一遍。

下面的代码示例展示了浅拷贝的实际效果。

# ================================================================
# === ShallowCopy.py =============================================
# ================================================================
#
class Foo:
    def __init__(self, data):
        self._data = data

aa = Foo ('aaa')
bb = Foo ('bbb')

# The initial list has two elements containing 'aaa' and 'bbb'
OldList = [aa,bb]
print OldList[0]._data

# The shallow copy makes a new list pointing to the old elements
NewList = OldList[:]
print NewList[0]._data

# Updating one of the elements through the new list sees the
# change reflected when you access that element through the
# old list.
NewList[0]._data = 'xxx'
print OldList[0]._data

# Updating the new list to point to something new is not reflected
# in the old list.
NewList[0] = Foo ('ccc')
print NewList[0]._data
print OldList[0]._data

在 Python 的命令行中运行这段代码会得到以下结果。我们可以看到新列表是通过复制旧对象创建的。旧列表中的某个对象可以通过引用来更新状态,而通过旧列表访问时可以看到这些更新。最后,改变新列表中的引用不会影响旧列表,因为新列表现在指向了一个不同的对象。

>>> # ================================================================
... # === ShallowCopy.py =============================================
... # ================================================================
... #
... class Foo:
...     def __init__(self, data):
...         self._data = data
...
>>> aa = Foo ('aaa')
>>> bb = Foo ('bbb')
>>>
>>> # The initial list has two elements containing 'aaa' and 'bbb'
... OldList = [aa,bb]
>>> print OldList[0]._data
aaa
>>>
>>> # The shallow copy makes a new list pointing to the old elements
... NewList = OldList[:]
>>> print NewList[0]._data
aaa
>>>
>>> # Updating one of the elements through the new list sees the
... # change reflected when you access that element through the
... # old list.
... NewList[0]._data = 'xxx'
>>> print OldList[0]._data
xxx
>>>
>>> # Updating the new list to point to something new is not reflected
... # in the old list.
... NewList[0] = Foo ('ccc')
>>> print NewList[0]._data
ccc
>>> print OldList[0]._data
xxx
51

就像NXC说的,Python中的变量名其实是指向一个对象,而不是内存中的某个特定位置。

newList = oldList 这行代码会创建两个不同的变量,它们都指向同一个对象。因此,如果你改变了 oldList,那么 newList 也会跟着改变。

但是,当你使用 newList = oldList[:] 时,它会对列表进行“切片”,并创建一个新的列表。这里的 [:] 默认值是从0开始到列表的末尾,所以它会把所有的内容都复制过来。因此,这样就会创建一个新的列表,里面包含了第一个列表的所有数据,但你可以分别修改这两个列表,而不会互相影响。

撰写回答