【问题标题】:Do Python for loops work by reference?Python for 循环是否通过引用工作?
【发布时间】:2013-02-11 15:03:30
【问题描述】:

在 Python 中使用 for 循环遍历列表中的项目时,更改 item(下)是否会更改 items 中的相应项目?

for item in items:
    item += 1

items 中的每一项是递增还是保持与循环前相同?

[注意:我会对 Python 2.7 和 3.x 感兴趣]

【问题讨论】:

  • 你为什么不试试呢?
  • 不;这previous answer of mine 有帮助吗?
  • @MartijnPieters -- 这不是取决于item 实际上是什么类型的对象吗?如果items 是具有适当定义的__iadd__ 的类实例怎么办?
  • @mgilson:啊,问题已编辑。之前是item = item + 1的作业。
  • Martijn Pieters 已经回答了您的问题,但与周边相关,这是 Pythonic 的做法:items = [x + 1 for x in items]

标签: python


【解决方案1】:

不,Python 中的变量不是指针。

它们改为引用堆上的对象,并且分配给变量不会更改引用的对象,而是变量。变量和对象就像绑在气球上的标签; assignment 将标签重新绑定到不同的气球。

请参阅此previous answer of mine 以进一步探索气球和标签的想法。

也就是说,一些对象类型实现了特定的就地添加行为。如果对象是可变的(气球本身可以改变),那么就地添加可以被解释为突变而不是赋值。

因此,对于整数,item += 1item = item + 1 完全相同,因为整数是不可变的。您必须创建一个新的整数对象并将item 标签绑定到该新对象。

另一方面,列表可变的,lst += [other, items] 被实现为lst.__iadd__([other, items]),这改变了lst 气球本身。分配仍然发生,但它是同一对象的重新分配,因为.__iadd__() 方法只是返回self 而不是一个新对象。我们最终将标签重新绑定到同一个气球。

循环只是在每次迭代时为您提供对列表中下一项的引用。它不允许您更改原始列表本身(这只是另一组气球标签);相反,它会为包含的每个项目提供一个新标签。

【讨论】:

  • 最具体地说,它不是一个突变后跟一个赋值吗?您在函数中改变对象,然后对该函数返回的任何内容进行分配(应该只是对象本身,但不一定是)? -- 也就是说i += somethingi = i.__iadd__(something)是一回事
  • @mgilson:是的,.__iadd__() 在这种情况下预计会返回 self
  • 是的,应该是,但不是必须的。我觉得指出这一点很有启发性,因为它非常清楚地解释了如何使用带有可变和不可变对象的+= 获得不同的行为。
【解决方案2】:

嗯,这真的取决于项目。

举个例子:

class test():
    pass

a = test()
a.value = 1

b = test()
b.value = 2

l = [a,b]

for item in l:
    item.value += 1

for item in l:
    print item.value

>>> 
2
3

在这种情况下:

l2 = [1,2,3]

for item in l2:
    item += 1

for item in l2:
    print item

>>> 
1
2
3

所以如你所见,你需要理解Martijn所说的指针。

【讨论】:

  • 你是对的,它在技术上取决于项目(即__iadd__的定义)。但不是你展示的方式:项目分配总是是这样工作的。您展示的是属性分配与本地分配不同,但这是完全不同的事情(尽管相关且也很重要)。 -1
  • 这是不正确的;您没有分配给局部变量,而是分配给另一个对象的属性。那是改变可变对象,而不是局部变量。
  • 我从未声明过,只是表明在 python 中迭代列表时,您可以在某些情况下处理项目,在其他语言中,不允许操作您正在迭代的对象/列表.
  • 好的,但这不会使您的答案与问题更相关。 (另请注意,您不会改变列表,您只是改变从多个位置引用的对象,其中一个恰好是列表中的一个插槽。)
  • OPs 的问题在目的或他的愿望上含糊不清。我只知道 OP 想要遍历一个列表,并询问“在 python 中”导致我理解“与其他语言相反”,所以我提供了两个示例,一个用于迭代和更改工作,一个用于它不不。我希望它可以指导 OP,或者至少尝试以某种方式通知他。
猜你喜欢
  • 2022-07-07
  • 2019-06-20
  • 2011-10-28
  • 2020-12-10
  • 2018-07-24
  • 1970-01-01
  • 2020-10-17
  • 1970-01-01
  • 2015-05-21
相关资源
最近更新 更多