3

这里有几个列表:a、b 等我想分别对它们进行一些更改,但我对 for 循环的行为感到困惑。

例如:如果我们这样做

a, b = range(5), range(5,10)
for x in [a, b]: x += [0]
print(a,b)

我们得到

([0, 1, 2, 3, 4, 0], [5, 6, 7, 8, 9, 0])

a,b 被修改。

但如果我们这样做

a, b = range(5), range(5,10)
for x in [a, b]: x = x + [0]
print(a,b)

我们得到

([0, 1, 2, 3, 4], [5, 6, 7, 8, 9])

a,b 未修改。我很困惑,x和a之间有什么关系?何时或如何使用 x 修改 a 的值?顺便问一下,a+=b 和 a=a+b 有什么区别?

无论如何,我找到了一个我们可以这样做的解决方案

a, b = range(5), range(5,10)
lis = [a, b]
for i, x in enumerate(lis): 
    lis[i] = ...

然后我们可以修改 a & b 的值。但是这种方法需要做一个额外的列表。

还有另一种解决方案

for x in ['a', 'b']:
    exec(x + '=' + x + '+ ...')

还有一个更简单的解决方案

a, b = range(5), range(5,10)
for x in [a, b]: x[:] = x + [0]
print(a,b)

我们会发现 a,b 被修改了:)

4

2 回答 2

7

这种关系与 Python 中的所有变量绑定相同。名称绑定到值。您看到的差异是因为您在做不同的事情,有时是对值进行操作,有时是对名称进行操作。

对于列表,+=就地扩展列表——也就是说,它修改了原始列表。因此,修改在使用该列表的任何地方都是可见的。

当您这样做时x = x + [0],您将名称重新绑定x到一个新列表(通过添加旧列表加号形成[0])。这不会修改原始列表,因此使用该列表的其他地方不会看到更改。

如果您搜索有关“变量”、“名称”、“值”、“引用调用”等的 Python 问题,您会发现有关此的其他讨论。 是一个在函数参数绑定的上下文中讨论类似问题的问题。for循环变量绑定的原理是一样的。

于 2013-03-12T06:03:47.813 回答
3

该行:

x += something

更改列表,同时:

x = x + something

x通过加入和创建一个全新的列表something

这与下面的简化演示没有什么不同:

>>> a = [7]      # The object is [7], name a is connected to it.
>>> x = a        # Now name x is also connected.
>>> x += [2]     # Here we change the backing object (behind a AND x).
>>> a            # So that both names seem to change.
[7, 2]
>>> x
[7, 2]

>>> a = [7]      # The object is [7], name a is connected to it.
>>> x = a        # Now name x is also connected.
>>> x = x + [2]  # Here we create a NEW object from the old one, and connect x.
>>> a            # So a is unchanged.
[7]
>>> x            # But x IS changed.
[7, 2]

这是我在 Python 中不得不习惯的最困难的事情,事实上名称和名称所指的对象是完全不同的,并且经常会以令人惊讶的方式行事。一旦你把它弄明白,它也是它最美丽的功能之一。

I eventually just started thinking that names were C pointers and all objects were on the heap (since that was where I have my expertise). There may be better ways to think of it, though I've never found any for me.

于 2013-03-12T06:11:02.253 回答