简体   繁体   English

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

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

This is quoted from the link : http://www.python-course.eu/for_loop.php - To avoid these side effects, it's best to work on a copy by using the slicing operator, as can be seen in the next example: 这是从链接中引用的: 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

The output is : 输出为:

['red', 'black']

My question is: does the statement colours[:] makes a copy of the colours list and the for loop works on the copy instead of the original list? 我的问题是:语句colours[:]创建了颜色列表的副本,并且for循环在副本上而不是原始列表上起作用? If it is so, then how the ["balck"] is appended to the original colour list? 如果是这样,那么如何将["balck"]附加到原始颜色列表?

does the statement colours[:] makes a copy of the colours list : Yes. 语句colours[:]复制颜色列表 :是。

and the for loop works on the copy instead of the original list? 和for循环适用于副本而不是原始列表? Yes, but be careful what you mean by "works on". 是的,但是请小心“继续工作”的含义。 The variable i takes its values from a copy of list colours . 变量i从列表colours的副本中获取其值。 However, the references to colours such as in the line colours += ["black"] refer to the original list. 但是,对colours的引用(例如线条colours += ["black"]是指原始列表。 That is just what the code wants, so it works. 这正是代码想要的,因此它可以工作。

If it is so, then how the ["balck"] is appended to the original colour list? 如果是这样,那么如何将[“ balck”]附加到原始颜色列表? This is because the line that does the appending refers to the original list and not the copy of the list. 这是因为进行添加的行引用的是原始列表,而不是列表的副本。

colours[:] makes a copy of the original list and iterates over it, but colours remains the original list. colours[:]复制原始列表并对其进行迭代,但是colours仍然是原始列表。 The following code would be equivalent: 以下代码是等效的:

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

This is the code you are referring to in the link provided: 这是您在提供的链接中引用的代码:

If you loop over a list, it's best to avoid changing the list in the loop body. 如果遍历列表,最好避免在循环主体中更改列表。 To give you an example, what can happen, have a look at the following example: 为了给您提供示例,可能发生的情况,请看以下示例:

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

What will be printed by "print colours"? “印刷颜色”将印刷什么?

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

To avoid these side effects, it's best to work on a copy by using the slicing operator, as can be seen in the next example : 为了避免这些副作用,最好使用切片运算符来处理副本,如以下示例所示

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']

We still might have done something, what we shouldn't have done. 我们可能仍然做了一些我们不应该做的事情。 We changed the list "colours", but our change hasn't had any effect on the loop anymore. 我们更改了列表“颜色”,但是更改对循环没有任何影响。 The elements to be looped remained the same during the iterations. 在迭代过程中,要循环的元素保持不变。

So: 所以:

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"]

Now no copy: 现在没有副本:

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']

Now an even worse case: 现在更糟的情况是:

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) 

What you are doing is completely different to what the example is trying to show, it is trying to avoid adding elements to the list you are iterating over so you only evaluate elements from the original list not newly added elements. 您正在执行的操作与该示例试图显示的完全不同,它试图避免将元素添加到要迭代的列表中,因此您只评估原始列表中的元素,而不评估新添加的元素。 You are trying to create a new list: 您正在尝试创建新列表:

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)

You should also append not += : 您还应该append+=

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM