如何在 python 的列表中使用切片运算符避免 for 循环中的副作用?

How to avoid side effect in for loop using slicing operator in a list in python?

这是引用自 link : http://www.python-course.eu/for_loop.php - 为避免这些副作用,最好使用切片运算符处理副本,如下例所示:

colours = ["red"]
for i in colours[:]:
    if i == "red":
        colours += ["black"]
    if i == "black":
        colours += ["white"]
print colours

输出为:

['red', 'black']

我的问题是:语句 colours[:] 是否复制了颜色列表并且 for 循环在副本而不是原始列表上工作?如果是这样,那么 ["balck"] 是如何附加到原始颜色列表的?

colours[:] 复制原始列表并对其进行迭代,但 colours 仍然是原始列表。以下代码是等效的:

copy = colours.copy()
for i in copy:
    if i == "red":
        colours.append("black")  # append is O(1)
    if i == "black":
        colours.append("white")

语句colours[:]是否复制颜色列表:是。

并且 for 循环适用于副本而不是原始列表? 是的,但请注意 "works on" 的意思。变量 i 从列表 colours 的副本中获取其值。但是,对 colours 的引用(例如 colours += ["black"] 行中的引用)指的是原始列表。这正是代码想要的,所以它有效。

如果是这样,那么["balck"]是如何追加到原来的颜色列表中的?这是因为追加的那一行是指原始列表而不是列表的副本。

这是您在 link 中引用的代码:

如果循环列表,最好避免在循环体中更改列表。举个例子,看看会发生什么,看看下面的例子:

colours = ["red"]
for i in colours:
    if i == "red":
        colours += ["black"]
    if i == "black":
        colours += ["white"]
print colours

"print colours"会打印什么?

['red', 'black', 'white']

为避免这些副作用,最好使用切片运算符处理副本,如下例所示:

colours = ["red"]
for i in colours[:]:
    if i == "red":
        colours += ["black"]
    if i == "black":
        colours += ["white"]
print colours
Now the output looks like this:
['red', 'black']

我们可能还是做了一些不该做的事情。我们更改了列表 "colours",但我们的更改对循环没有任何影响了。要循环的元素在迭代期间保持不变。

所以:

colours = ["red"]
for i in colours[:]: # iterates over a copy so we only evaluate what is in the list originally
    if i == "red":
        colours += ["black"]
    if i == "black":
        colours += ["white"]
print(colours) # ["red", "black"]

现在没有副本:

colours = ["red"]
for i in colours:
    if i == "red":
        colours += ["black"] # black gets added, colours -> ["red", "black"]
    if i == "black": # now because of ^^, white gets added.
        colours += ["white"]
print(colours) # -> ['red', 'black', 'white']

现在更糟糕的情况是:

colours = ["red"]
for i in colours:
    if i == "red":
        colours += ["red"] # red gets add, colours = ["red", "red"]
                          # 2nd iteration, red gets added, colours ->  colours = ["red", "red", "red"]
                          # infinite loop....
    if i == "black":
        colours += ["white"]
print(colours) 

您所做的与示例试图展示的完全不同,它试图避免向您正在迭代的列表中添加元素,因此您只评估原始列表中的元素而不是新添加的元素。您正在尝试创建一个新列表:

colours = ["red"]
new = colours[:] # assign new list/copy to a name.
for i in colours:
    if i == "red":
        new += ["red"] # add to new list
    if i == "black":
        new += ["white"]
print(colours)

你也应该 append 而不是 +=:

colours = ["red"]
new = colours[:]
for i in colours:
    if i == "red":
        new.append("red")
    if i == "black":
        new.append("white")
print(colours)