简体   繁体   English

交换 Python 中的变量和列表元素意外工作

[英]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 . lsa和第一个元素都是对 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.从字面上看, als[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.虽然它们在表达式中使用时评估为对象,但这并不会使它们与这些对象相同——并且“它们的”对象的身份也不会扩展到它们。

  • The expression a is ls[0] means "evaluate a and ls[0] and compare the result for identity".表达式a is ls[0]的意思是“评估als[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".值得注意的是,在赋值语句中使用时, als[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同时使用als[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现在会将a12重新分配为具有值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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM