【问题标题】:Python: change a list via for-loop [duplicate]Python:通过for循环更改列表[重复]
【发布时间】:2018-12-01 20:14:17
【问题描述】:

我又来问你另一个基本问题。 :) 我想通过 for-loop 更改列表。(抱歉打扰,但我是新人....)

这是第一个脚本:

L=[1,2,3]
i=0
for a in L:
    L[i]+=1
    i+=1
print(L)
print(a)

我明白了:

L:[2,3,4]
a: 3

这正是我想要的。 但我注意到,如果我将脚本更改为:

L=[1,2,3]
for i in L:
    i+=1
print(L)
print(i)

我得到了:

L:[1,2,3]
i:4

我可以理解我必须是 4。但问题是为什么列表 L 没有改变。在我看来,列表中的对象被赋予变量 i。所以变量 i 是可以编辑对象的那个。所以基本上,列表应该改变。但实际上,它保持不变。

谁能解释一下?

谢谢!

【问题讨论】:

  • i 只是一个循环变量。为什么您认为更改 i 应该更改列表中的值?
  • 根据您的代码 sn-p,列表“L”不应更改,因为“i”只是一个可验证的计数器,每次迭代时都包含“L”中的单个元素。跨度>
  • @Austin,@Sonam Mohite,因为我认为列表中的元素(对象)被赋予了变量 i。这与 i = L[0], i =2 相同。那么L[0]=2
  • @Harry 你可以在上面的链接中找到为什么值没有改变
  • 好的!谢谢!我去看看

标签: python


【解决方案1】:

但问题是为什么列表 L 没有改变

因为如果您将任何内容分配给i,它不会影响L[i]

解决方案要么是您所拥有的proposed,要么是looping,通过索引

for index, item in enumerate(L):

另一种方法是使用列表推导

L[:] = [i + 1 for i in L]

【讨论】:

  • 我明白了,但我认为该列表是可变的。我可以更改原始列表的值,而不是进行一些更改并将其复制到新列表中?
  • L = [i + 1 for i in L] 不会更改列表,因此它不会执行 OP 的要求。它必须是L[:] = [i + 1 for i in L]
【解决方案2】:

当你做你的循环时

for i in L :
    i+=1

你永远不会要求 Python 改变你的列表 L。事实上,你只是更新 i。 起初,i = L[0] = 1,你将 i 更新为 2。但 L 没有改变,因为你没有要求更新 L[0]。由于 L 包含数字,当你做for i in L 时,那么 i 不是 L 本身的元素,而是它的克隆。

正确的做法是:

for i in range(len(L)) :
    L[i] += 1 #you update L[i] itself this time

或者如果你喜欢更紧凑的方式:

L = [i+1 for i in L]

我希望我已经足够清楚了。 祝你有美好的一天;-)

【讨论】:

  • "当你在 L 中为 i 做时,那么 i 不是 L 本身的元素,而是它的克隆。" => 错了。好吧,大部分是错误的...i 指向的是列表的元素,但 rebinding name i 不会更改列表。有关更深入的解释,请参阅nedbatchelder.com/text/names.html
  • @brunodesthuilliers,谢谢!我同意你的看法
  • 哦,顺便说一句,您最后的“正确方式”与 OP 要求的不同 - 它重新绑定 L 但不会更改 L 指向的列表,所以对这份原始清单的其他引用将保持不变。您希望 L[:] = [i+1 for i in L] 具有相同的行为(更新列表)。
  • @Kwikerr 你真的需要学习 Ned 的文章。另见python.net/~goodger/projects/pycon/2007/idiomatic/…
  • @Kwikerr 在这种情况下,扩充的赋值运算符被覆盖以执行 list.extend() 操作并返回 LHS 列表 - 所以你实际上有两个重新绑定操作(它本身不会改变 @ 987654333@) 和列表i 的突变指向。将i += [1] 替换为i.extend([1]),您将拥有真正的行为。如果你真的想理解 python 的“变量”,你必须完全忘记传统的 C/Pascal/etc 对“变量”的定义(其中变量是内存地址),并从“名称”和“绑定”的角度来思考。
【解决方案3】:
for i in L:

这意味着在迭代列表时,列表中每个元素的值都存储在 i 中。

因此,如果您更改 i 的值,列表中将不会发生任何变化

考虑一下-

a=2
b=a
b=3

改变 b 不会改变 a 的值。

【讨论】:

  • 谢谢!我理解这一点,但这是针对整数变量。整数本来就不能改变。但列表可以更改。
  • 你能解释一下 Integer can't be changed original 是什么意思吗?
  • @KeshavBansal python 整数是不可变的,列表是可变的。并且说“列表中的元素存储在 i 中”充其量是一种误导,实际上从技术 POV 来看是完全错误的——“i”只是一个名称,而不是内存地址,所以没有任何东西“存储在”它。
【解决方案4】:

这与 Python “变量”的真正含义有关:名称指向对象。将其视为以名称为键、对象为值的字典。

在您的for 循环中,i 最初指向列表中的当前迭代项,即i 指向L[0],然后指向L[1] 等。但是当您执行i += 1 - 时实际上转换为i = i+1 - 你重新绑定i 使其指向另一个对象。这只会影响 name i(键持有什么值),而不影响它之前指向的对象,因此您的列表确实没有改变。

如需更深入的解释,请阅读Ned Batchelder's excellent article。这将为您节省很多时间和挫折;)

注意:对于您的示例 sn-p,更新列表的正确方法是使用 enumerate:

for index, value in enumerate(L):
    L[index] = value + 1

或使用列表推导就地更新整个列表:

L[:] = [value+1 for value in L]

【讨论】:

  • 是的!多么完美的解释!谢谢!
  • @Harry 我赞同 Bruno 的建议,即阅读 Ned 的文章。实际上,当我阅读您的问题时,我几乎在评论中发布了该文章的链接,直到我看到它已经在此答案中链接。 Other languages have "variables", Python has "names" 有一篇简短的文章,其中包含关于这个重要主题的漂亮图表。
  • @PM2Ring,谢谢!我会看看的!谢谢!
【解决方案5】:

感谢您的所有回答!但是这个链接真的很全面。 https://nedbatchelder.com/text/names.html 这与以下内容相同:

m=[1,2,3]
i=m[0]  #here i refers to m[0], namely 1
i=4     #here i refers to a new value

结果显然是:

m=[1,2,3]
i=4

因为 int-name 原来不能更改。一旦 i 的值发生变化,它就会引用另一个值(对象)。所以列表不会改变。

谢谢大家。

【讨论】:

  • 如果你理解了 Ned 的文章,你就会明白为什么这个 3 行程序会这样做:lst = [[1],[2],[3]]for a in lst: a *= 2print(lst)
  • @PM2Ring!它重复了。谢谢!
猜你喜欢
  • 2020-05-22
  • 2018-07-18
  • 2018-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-18
相关资源
最近更新 更多