Python 如果切片复制引用,为什么会出现这种行为?

Python 如果切片复制引用,为什么会出现这种行为?,python,list,reference,slice,Python,List,Reference,Slice,根据,python在切片时复制引用。我尝试了以下方法: >>> a=[1,2,3] >>> b=a[:] >>> b[1]=0 >>> a [1, 2, 3] >>> b [1, 0, 3] >>> map(id,a) [14508376, 14508352, 14508328] >>> map(id,b) [14508376, 14508400, 14508328]

根据,python在切片时复制引用。我尝试了以下方法:

>>> a=[1,2,3]
>>> b=a[:]
>>> b[1]=0
>>> a
[1, 2, 3]
>>> b
[1, 0, 3]
>>> map(id,a)
[14508376, 14508352, 14508328]
>>> map(id,b)
[14508376, 14508400, 14508328]
为什么b[1]=0不会改变a[1],人们可能会想,如果b[1]确实是对同一对象的引用,那么这种情况应该会发生?相反,它似乎生成了一个新的引用/id并更改了新对象。我可以在任何地方更详细地了解这种行为吗?

假设您从a=[1,2,3]开始。在Python的数据模型中,这意味着a引用内存中的对象:

a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
使用b=a,您只需将另一个名称指向同一对象:

a -> [ * | * | * ] <- b
       |   |   |
       v   v   v
       1   2   3
a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^   ^   ^
       |   |   |
b -> [ * | * | * ]
2仍在内存中,可能通过其他名称直接或间接引用,但不再通过a或b引用

使用b=a[:],可以创建一个新列表,但该新列表包含对同一对象的引用:

a -> [ * | * | * ] <- b
       |   |   |
       v   v   v
       1   2   3
a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^   ^   ^
       |   |   |
b -> [ * | * | * ]
现在,当您编写b[1]=0时,您并没有更改a[1],因为a和b是不同的列表对象

a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^       ^
       |       |
b -> [ * | * | * ]
           |
           v
           0
Ned Batchelder及其后续文章是对Python名称模型的极好概述。

假设您从a=[1,2,3]开始。在Python的数据模型中,这意味着a引用内存中的对象:

a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
使用b=a,您只需将另一个名称指向同一对象:

a -> [ * | * | * ] <- b
       |   |   |
       v   v   v
       1   2   3
a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^   ^   ^
       |   |   |
b -> [ * | * | * ]
2仍在内存中,可能通过其他名称直接或间接引用,但不再通过a或b引用

使用b=a[:],可以创建一个新列表,但该新列表包含对同一对象的引用:

a -> [ * | * | * ] <- b
       |   |   |
       v   v   v
       1   2   3
a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^   ^   ^
       |   |   |
b -> [ * | * | * ]
现在,当您编写b[1]=0时,您并没有更改a[1],因为a和b是不同的列表对象

a -> [ * | * | * ]
       |   |   |
       v   v   v
       1   2   3
       ^       ^
       |       |
b -> [ * | * | * ]
           |
           v
           0

Ned Batchelder及其后续文章是对Python名称模型的极好概述。

作业也复制了引用。请参见.b[1]=0更改引用,而不是所引用的对象。所以现在这两个列表有不同的引用。当您看到列表中反映的更改时,并不是因为b中引用的更改更改了a中的引用,而是因为a和b中引用的对象都已更改。用表示引用的箭头绘制一些图片,这确实有帮助。@user2357112是的,但行为与什么不同?如果你是这么想的话,这肯定与复制引用的行为没有什么不同。@user2357112我的意思是c=a赋值,c[1]=0导致存在[1,0,3],这与使用切片时不同,a[:]赋值也复制引用。请参见.b[1]=0更改引用,而不是所引用的对象。所以现在这两个列表有不同的引用。当您看到列表中反映的更改时,并不是因为b中引用的更改更改了a中的引用,而是因为a和b中引用的对象都已更改。用表示引用的箭头绘制一些图片,这确实有帮助。@user2357112是的,但行为与什么不同?如果你是这么想的话,它肯定与复制引用的行为没有什么不同。@user2357112我的意思是c=a赋值,c[1]=0导致存在[1,0,3],这与使用切片a[:]