Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python列表切片语法没有明显的原因_Python_List_Shallow Copy - Fatal编程技术网

Python列表切片语法没有明显的原因

Python列表切片语法没有明显的原因,python,list,shallow-copy,Python,List,Shallow Copy,我偶尔会看到Python代码中使用的列表片段语法如下: newList = oldList[:] 当然,这与: newList = oldList 还是我遗漏了什么?[:]列表,复制包含对原始列表成员引用的列表结构。这意味着对副本的操作不会影响原件的结构。但是,如果对列表成员执行某些操作,两个列表仍然引用它们,因此如果通过原始列表访问成员,则会显示更新 A还将复制所有名单成员 下面的代码片段显示了一个正在运行的浅拷贝 # ===================================

我偶尔会看到Python代码中使用的列表片段语法如下:

newList = oldList[:]
当然,这与:

newList = oldList
还是我遗漏了什么?

[:]
列表,复制包含对原始列表成员引用的列表结构。这意味着对副本的操作不会影响原件的结构。但是,如果对列表成员执行某些操作,两个列表仍然引用它们,因此如果通过原始列表访问成员,则会显示更新

A还将复制所有名单成员

下面的代码片段显示了一个正在运行的浅拷贝

# ================================================================
# === 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
在pythonshell中运行它会得到以下脚本。我们可以看到 正在使用旧对象的副本制作列表。其中一个对象可以具有 其状态通过旧列表通过引用更新,并且可以 通过旧列表访问对象时看到。最后,更改 可以看出,新列表中的引用没有反映在旧列表中,因为 新列表现在引用的是另一个对象

>>> # ================================================================
... # === 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

正如NXC所说,Python变量名实际上指向一个对象,而不是内存中的特定位置

newList=oldList
将创建指向同一对象的两个不同变量,因此,更改
oldList
也将更改
newList


但是,当您执行
newList=oldList[:]
操作时,它会对列表进行“切片”,并创建一个新列表。
[:]
的默认值为0,位于列表的末尾,因此它会复制所有内容。因此,它创建了一个新列表,其中包含第一个列表中包含的所有数据,但两个列表都可以在不更改另一个列表的情况下进行更改。

由于已经回答了这个问题,我只需添加一个简单的演示:

>>> 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]

千万不要认为Python中的“a=b”意味着“将b复制到a”。如果两边都有变量,你就不可能真正知道这一点。相反,可以将其视为“给b额外的名称a”

如果b是一个不可变的对象(如数字、元组或字符串),那么是的,其效果是得到一个副本。但这是因为当你处理不可变(可能应该被称为只读、不可更改或蠕虫)时,根据定义,你总是会得到一个副本

如果b是可变的,你总是需要做一些额外的事情来确保你有一个真实的副本。总是。对于列表,它就像一个切片一样简单:a=b[:]

可变性也是导致以下情况的原因:

def myfunction(mylist=[]): 
    pass
。。。并不像你想象的那样

若你们来自C语言背景:“=”的左边总是一个指针。所有变量始终都是指针。如果你把变量放在一个列表中:a=[b,c],你就把指向b和c所指向的值的指针放在了a所指向的列表中。如果随后将a[0]=d,则位置0处的指针现在指向d指向的任何对象


另请参见复制模块:

浅层复制:(将内存块从一个位置复制到另一个位置)

深度复制:(复制对象引用)


哇!我不知道。非常有趣。正如在其他答案中提到的,这被称为“浅拷贝”。那么为什么“也可以分配到切片,这甚至可以改变列表的大小或完全清除它”?请参阅link()“两者都可以更改,而不必更改另一个”-这是正确的,因为所讨论的列表包含不可变的对象。如果它包含可变对象,则对
newList
中对象的更改将反映在
oldList
中,反之亦然-这是一个重要的区别。@jonrsharpe他没有说对一个对象的每一次更改都不会改变另一个对象。例如,即使列表中有可变对象,您也可以扩展一个列表,而这不会改变另一个列表。我想他指的是两个列表对象本身,而不是它们的内容。这是更好、更完整的答案。顺便说一句,我不喜欢“浅/深”的区别。它并没有真正抓住问题的复杂性。深度副本应该是其成员的浅层副本还是深度副本?实际上,当您需要复制一个复杂的对象图时,您通常希望克隆一些对象类型,而只复制对其他对象的引用。@Kos深度复制总是递归地深-如果您希望复制到某个点的深度,然后变为浅,您必须自己实现它(我不知道合适的术语是什么-“sand bar”复制?!)只是为了澄清-不要使用类型名作为变量名!这是邪恶的,可以给你几个小时的乐趣。如果你想获得一些列表的浅副本,请使用newList=list(aList)。这比aList[:]更合理谢谢。问题被相应地编辑了。我在我的博客上做了一个小例子:@Abgan
aList[:]怎么样
unsound?我认为说不可变对象“总是得到一个副本”是误导,因为不太可能发生任何复制。关键是让一个不可变对象有多个名称和一个副本一样好,因为它不能改变它的值。实际上,制作像st这样的不可变类型的真正副本是相当困难的环(例如)。这不是深度副本-深度副本是递归副本()。在列表的浅层副本中,该列表的子列表不会被复制,只会被重新引用。深度副本递归地下降到子列表和子列表中,并真正复制它们的所有条目。
a = ['one','two','three']

b = a[:]

b[1] = 2

print id(a), a #Output: 1077248300 ['one', 'two', 'three']
print id(b), b #Output: 1077248908 ['one', 2, 'three']
a = ['one','two','three']

b = a

b[1] = 2


print id(a), a #Output: 1077248300 ['one', 2, 'three']
print id(b), b #Output: 1077248300 ['one', 2, 'three']