交换 Python 中的变量和列表元素出乎意料

Swapping variables and list elements in Python works unexpectedly

我刚刚想出了一个代码示例:

ls = [2222, 1111]

a = ls[0]
print(a is ls[0])

a, ls[1] = ls[1], a
print(ls)

打印:

True
[2222, 2222]

我的问题是,为什么在上述情况下 als[0] 不是同一个对象? a is ls[0] 检查是 True,因此它必须与:

相同
ls[0], ls[1] = ls[1], ls[0]

但事实并非如此。后一个产生 [1111, 2222]。这是什么谜?

您没有设置 ls[0]!

正在修复:

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)

输出:

True
[2222, 2222]
[1111, 2222]

顺便说一句:您可以通过以下方式进行反向列表:

ls = [2222, 1111]
print(ls[::-1])

输出:

[1111, 2222]

此代码将不起作用,因为在这种情况下您引用了 ls[0] 处的对象,而不是对 ls[0].

的内存位置的引用

从字面上看,als[1] 都不是对象:它们分别是 identifier and subscription。虽然它们在表达式中使用时 评估为 对象,但这并不会使它们与这些对象相同——并且“它们的”对象的身份也不会扩展到它们。

  • 表达式a is ls[0]的意思是“计算als[0]并比较结果的同一性”。它不检查标识符 a 是否与订阅 ls[0].
  • 相同

值得注意的是,当在 assignment statement 中使用时,als[1] 都不代表“查找对象的表达式”,而是“分配对象的目标”到”。前者的特点不影响后者


语句 a, ls[1] = ls[1], a 同时使用 als[1] 作为表达式和目标:

  • 右边是一个表达式。它表示“评估 ls[1]a 的结果的元组”。

  • 左边是作业。它表示“分配给标识符a和订阅ls[1]”。

标识符的赋值始终是即时的:标识符之前引用的值是什么并不重要。具体来说,a 之前引用了一个也被 ls[0] 引用的对象并不重要,它的新指代也被 ls[1] 引用并不重要。


要理解为什么这种区别很重要,请考虑标识符与文字“相同”的情况:

>>> # integers < 256 are interned
>>> a = 12
>>> # identifier "is identical to" literal
>>> a is 12
True

如果表达式中的同一性等同于赋值中的同一性,那么设置 a = 13 现在会重新分配 a 12 以具有值 13.

简单赋值对目标的值没有影响。

之后

ls = [2222, 1111]

a = ls[0]

als的第一个元素都是对整数2222的引用。

作业

a, ls[1] = ls[1], a

实际上与

相同
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

您从未修改过 ls 的第一个元素;您只更改了 a 所指的内容以及 ls 的第二个元素所指的内容。您可以看到 a 现在指的是 1111,因为这就是 ls[1] 的值 ls[1] 被修改之前。

>>> print(a)
1111