[英]Swapping variables and list elements in Python works unexpectedly
I have just came up with an example of code:我刚刚想出了一个代码示例:
ls = [2222, 1111]
a = ls[0]
print(a is ls[0])
a, ls[1] = ls[1], a
print(ls)
which prints:打印:
True
[2222, 2222]
My question is, why isn't a
the same object as ls[0]
in the above case?我的问题是,为什么a
上述情况下 object 与ls[0]
不同? The a is ls[0]
check is True
, therefore it must be the same as: a is ls[0]
检查为True
,因此它必须与以下内容相同:
ls[0], ls[1] = ls[1], ls[0]
but it isn't.但事实并非如此。 The latter one produces [1111, 2222]
.后者产生[1111, 2222]
。 What is this mYsTeRy?这是什么奥秘?
Simple assignments have no affect on the previous value of the target.简单赋值对目标的先前值没有影响。
After后
ls = [2222, 1111]
a = ls[0]
both a
and the first element of ls
are references to the integer 2222
. ls
的a
和第一个元素都是对 integer 2222
的引用。
The assignment那作业
a, ls[1] = ls[1], a
is effectively the same as实际上与
t = ls[1], a # The tuple (1111, 2222)
a = t[0] # Set a to t[0] == 1111
ls[1] = t[1] # Set ls[1] to t[1] == 2222
At no point have you modified the first element of ls
;您从未修改过ls
的第一个元素; you've only changed what a
refers to and what the second element of ls
refers to.您只更改了a
所指的内容和ls
的第二个元素所指的内容。 You can see that a
is now refers to 1111
, since that's what the value of ls[1]
was before ls[1]
was modified.您可以看到a
现在指的是1111
,因为这是ls[1]
的值在ls[1]
被修改之前的值。
>>> print(a)
1111
You are not setting ls[0]!您没有设置 ls[0]!
Fixing it:修复它:
ls = [2222, 1111]
# Assigns ls[0] to a, but not changes ls[0]!
a = ls[0]
print(a is ls[0])
# Assigns ls[1] to a and a to ls[1]. At this point ls[1] is a!
a, ls[1] = ls[1], a
print(ls)
# Now ls[0] is assigned!
ls[0] = a
print(ls)
Outputs:输出:
True
[2222, 2222]
[1111, 2222]
BTW: You can do the reverse listing with:顺便说一句:您可以通过以下方式进行反向列表:
ls = [2222, 1111]
print(ls[::-1])
Outputs:输出:
[1111, 2222]
Taken literally, neither a
nor ls[1]
are objects: They are an identifier and subscription , respectively.从字面上看, a
和ls[1]
都不是对象:它们分别是标识符和订阅。 While they evaluate to objects when used in an expression, that does not make them identical to these objects – and the identity of "their" objects does not extend to them, either.虽然它们在表达式中使用时评估为对象,但这并不会使它们与这些对象相同——并且“它们的”对象的身份也不会扩展到它们。
a is ls[0]
means "evaluate a
and ls[0]
and compare the result for identity".表达式a is ls[0]
的意思是“评估a
和ls[0]
并比较结果的身份”。 It does not check whether the identifier a
is identical to the subscription ls[0]
.它不检查标识符a
是否与订阅ls[0]
相同。 Notably, when used in an assignment statement , both a
and ls[1]
do not represent "an expression to look up an object" but rather "a target to assign an object to".值得注意的是,在赋值语句中使用时, a
和ls[1]
都不是表示“查找对象的表达式”,而是表示“将 object 分配给的目标”。 The features of the former do not impact the latter.前者的特点不影响后者。
The statement a, ls[1] = ls[1], a
uses both a
and ls[1]
as both expressions and targets:语句a, ls[1] = ls[1], a
同时使用a
和ls[1]
作为表达式和目标:
The right hand side is an expression.右手边是表情。 It represents "a tuple of the results of evaluating ls[1]
and a
".它表示“评估ls[1]
和a
的结果的元组”。
The left hand side is an assignment.左边是作业。 It represents "assign to the identifier a
and the subscription ls[1]
".它表示“分配给标识符a
和订阅ls[1]
”。
Assignment to an identifier always is immediate: it does not matter what value the identifier previously referred to.对标识符的分配总是立即的:标识符先前引用的值无关紧要。 Specifically, it does not matter that a
previously referred to an object that was also referred to by ls[0]
, and it will not matter that its new referent was also referred to by ls[1]
.具体来说, a
之前引用的 object 也被ls[0]
引用并不重要,并且它的新所指对象也被ls[1]
引用也没关系。
To understand why this distinction is important, consider the case that an identifier "is identical to" a literal:要理解为什么这种区别很重要,请考虑标识符“等同于”文字的情况:
>>> # integers < 256 are interned
>>> a = 12
>>> # identifier "is identical to" literal
>>> a is 12
True
If identity in expressions would equate to identity in assignments, then setting a = 13
would now reassign both a
and 12
to have the value 13
.如果表达式中的标识等同于赋值中的标识,那么设置a = 13
现在会将a
和12
重新分配为具有值13
。
This code would not work as in this case you have a reference to the object at ls[0]
and not a reference to the memory position of ls[0]
.此代码将不起作用,因为在这种情况下,您在ls[0]
处引用了 object 而不是对ls[0]
的 memory position 的引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.