在python中将列表项分配给变量时感到困惑

在python中将列表项分配给变量时感到困惑,python,list,variables,reference,Python,List,Variables,Reference,假设我有一张清单: L = [1,2,3] 我把L[0]赋值给变量a 那么如果我改变a,它不会影响L 为什么会这样?python不是在传递所有引用吗?我认为a指向L[0]因为在你的例子中L[0]是,更改a不会影响L[0]的值。更改时,将创建新对象,并开始指向该对象 查看L[0]是可变类型时会发生什么: >>> L = [[1],2,3] >>> a = L[0] >>> a.append(2) >>> L [[1, 2],

假设我有一张清单:

L = [1,2,3]
我把L[0]赋值给变量a

那么如果我改变a,它不会影响L

为什么会这样?python不是在传递所有引用吗?我认为a指向L[0]

因为在你的例子中L[0]是,更改a不会影响L[0]的值。更改时,将创建新对象,并开始指向该对象

查看L[0]是可变类型时会发生什么:

>>> L = [[1],2,3]
>>> a = L[0]
>>> a.append(2)
>>> L
[[1, 2], 2, 3]
在这种情况下,a和L[0]都指向同一个对象

>>> a, L[0]   
(2, 1)
另请参见。

中的,因为在您的情况下,L[0]是,更改a不会影响L[0]的值。更改时,将创建新对象,并开始指向该对象

查看L[0]是可变类型时会发生什么:

>>> L = [[1],2,3]
>>> a = L[0]
>>> a.append(2)
>>> L
[[1, 2], 2, 3]
在这种情况下,a和L[0]都指向同一个对象

>>> a, L[0]   
(2, 1)
另请参见。

中的问题在于a和L[0]是对不可变对象的引用,因此更改其中任何一个都不会影响其他引用:

>>> L = [1, 2, [3]]
>>> a = L[0]
>>> a = a + 1
>>> b = L[2]
>>> b.append(4)  #list.append is an in-place operation
>>> b, L[2]
([3, 4], [3, 4])

>>> b = b + [5]  #mutable object, but not an in-place operation 
>>> b            #b is assigned to new list object
[3, 4, 5]
>>> L[2]         #L[2] is unchanged
[3, 4]
a现在指向一个新对象,而L[0]仍然指向同一对象

>>> a, L[0]   
(2, 1)
在这种情况下,b和L[2]是对可变对象列表的引用,对它们的任何就地操作都会影响所有引用:

>>> L = [1, 2, [3]]
>>> a = L[0]
>>> a = a + 1
>>> b = L[2]
>>> b.append(4)  #list.append is an in-place operation
>>> b, L[2]
([3, 4], [3, 4])

>>> b = b + [5]  #mutable object, but not an in-place operation 
>>> b            #b is assigned to new list object
[3, 4, 5]
>>> L[2]         #L[2] is unchanged
[3, 4]
问题是a和L[0]是对不可变对象的引用,因此更改其中任何一个都不会影响其他引用:

>>> L = [1, 2, [3]]
>>> a = L[0]
>>> a = a + 1
>>> b = L[2]
>>> b.append(4)  #list.append is an in-place operation
>>> b, L[2]
([3, 4], [3, 4])

>>> b = b + [5]  #mutable object, but not an in-place operation 
>>> b            #b is assigned to new list object
[3, 4, 5]
>>> L[2]         #L[2] is unchanged
[3, 4]
a现在指向一个新对象,而L[0]仍然指向同一对象

>>> a, L[0]   
(2, 1)
在这种情况下,b和L[2]是对可变对象列表的引用,对它们的任何就地操作都会影响所有引用:

>>> L = [1, 2, [3]]
>>> a = L[0]
>>> a = a + 1
>>> b = L[2]
>>> b.append(4)  #list.append is an in-place operation
>>> b, L[2]
([3, 4], [3, 4])

>>> b = b + [5]  #mutable object, but not an in-place operation 
>>> b            #b is assigned to new list object
[3, 4, 5]
>>> L[2]         #L[2] is unchanged
[3, 4]
L[0]是一个名称,在创建列表L时,为该名称指定一个对象,即整数1。a也是一个名称,当您在a=L[0]中指定a时,将a指向L[0]指向的同一对象

但当你以后做a=a+1时,这是另一个赋值。您没有修改指向的对象-符号=不能这样做。您正在创建一个新对象,即整数2,并将其指定给

最后,你的记忆中有两个对象;一个由L[0]引用,另一个由a引用

整数是不可变的,这意味着在本例中没有可能的方法更改对象的属性;然而,这在本例中并不突出,因为即使对象是可变的,它也不会改变您使用=符号进行赋值的事实。在所讨论的对象是可变的情况下,理论上可以在对象仍被L[0]和a引用时更改对象的属性,而不是像现在这样使用=进行任何附加赋值。此时,无论您使用哪个名称检查对象,您都会看到属性发生更改。

L[0]是一个名称,当您创建列表L时,您将为该名称指定一个对象,即整数1。a也是一个名称,当您在a=L[0]中指定a时,将a指向L[0]指向的同一对象

但当你以后做a=a+1时,这是另一个赋值。您没有修改指向的对象-符号=不能这样做。您正在创建一个新对象,即整数2,并将其指定给

最后,你的记忆中有两个对象;一个由L[0]引用,另一个由a引用


整数是不可变的,这意味着在本例中没有可能的方法更改对象的属性;然而,这在本例中并不突出,因为即使对象是可变的,它也不会改变您使用=符号进行赋值的事实。在所讨论的对象是可变的情况下,理论上可以在对象仍被L[0]和a引用时更改对象的属性,而不是像现在这样使用=进行任何附加赋值。此时,无论您使用哪个名称检查对象,都会看到属性发生更改。

将分配更改为:

a = L
然后,当您将L更改为:

L[0] += 1

您将看到a也发生了变化。这是参考魔法。

将分配更改为:

a = L
然后,当您将L更改为:

L[0] += 1

您将看到a也发生了变化。这就是参考魔法。

看看这个答案,我认为你可以找到你问题的答案,否则让我知道看看这个答案,我认为你可以找到你问题的答案,否则让我知道我认为说=不能修改任何东西并不准确。虽然L[0]=foo确实在不修改的情况下替换了L[0]中的旧值,但它确实改变了列表L。@Blckknght感谢您指出这一点。并不是说=不能修改任何东西,因为赋值本身可以修改对象。但是=无法修改由其操作的名称引用的对象。它根本不需要取消对名称本身的引用-尽管在L[0]或例如obj.foo的情况下,必须取消对L或obj的引用才能执行a
分配。如果所讨论的名称是一个属性,那么可能会发生一些棘手的事情,即属性的所有者直接进行变异以代替赋值,但这是一个相当高级的讨论主题。我认为说=不能修改任何内容并不准确。虽然L[0]=foo确实在不修改的情况下替换了L[0]中的旧值,但它确实改变了列表L。@Blckknght感谢您指出这一点。并不是说=不能修改任何东西,因为赋值本身可以修改对象。但是=无法修改由其操作的名称引用的对象。它根本不需要取消对名称本身的引用-尽管在L[0]或例如obj.foo的情况下,必须取消对L或obj的引用才能进行赋值。如果所讨论的名称是一个属性,那么可能会发生一些棘手的事情,其中属性的所有者正在进行直接的变异来代替赋值,但这是一个相当高级的讨论主题。