Python 从内部向列表追加和删除实例

Python 从内部向列表追加和删除实例,python,python-3.x,list,object,Python,Python 3.x,List,Object,下面的代码定义了一个类(Wall),当它被实例化时,对象被添加到一个列表中(正在进行),一旦它的属性(progress)达到3,它就会从该列表中删除并移动到另一个列表中(构建) 这很方便,因为无论“正在进行”列表中有多少墙,我都可以运行: for wall in in_progress: wall.build() 最终,“进行中”将是空的。然而,我做了一些测试,当一个正在进行的实例达到progress=3时,会发生一些奇怪的事情 比如说。让我们举例说明三面墙: Wall() Wall(

下面的代码定义了一个类(Wall),当它被实例化时,对象被添加到一个列表中(正在进行),一旦它的属性(progress)达到3,它就会从该列表中删除并移动到另一个列表中(构建)

这很方便,因为无论“正在进行”列表中有多少墙,我都可以运行:

for wall in in_progress:
    wall.build()
最终,“进行中”将是空的。然而,我做了一些测试,当一个正在进行的实例达到progress=3时,会发生一些奇怪的事情

比如说。让我们举例说明三面墙:

Wall()
Wall()
Wall() 

#check in_progress
in_progress
--->
[<__main__.Wall at 0x7f4b84e68cf8>,
 <__main__.Wall at 0x7f4b84e68c50>,
 <__main__.Wall at 0x7f4b84e68f28>]

#check attribute progress

for wall in in_progress:
    print(f'{wall}: {wall.progress}')
--->
<__main__.Wall object at 0x7f4b84e68cf8>: 0
<__main__.Wall object at 0x7f4b84e68c50>: 0
<__main__.Wall object at 0x7f4b84e68f28>: 0

#'build' on them 2 times
for wall in in_progress:
    wall.build()

for wall in in_progress:
    print(f'{wall}: {wall.progress}')
--->
<__main__.Wall object at 0x7f4b84e68cf8>: 2
<__main__.Wall object at 0x7f4b84e68c50>: 2
<__main__.Wall object at 0x7f4b84e68f28>: 2
Wall()
墙()
墙()
#办理登机手续
进行中
--->
[,
,
]
#检查属性进度
对于正在进行的墙:
打印(f'{wall}:{wall.progress}')
--->
: 0
: 0
: 0
#“构建”它们两次
对于正在进行的墙:
wall.build()
对于正在进行的墙:
打印(f'{wall}:{wall.progress}')
--->
: 2
: 2
: 2
如果我们再次运行上一个代码,我们会发现进程中的列表为空,但我们发现的是:

#'build' on them once more
for wall in in_progress:
    wall.build()

for wall in in_progress:
    print(f'{wall}: {wall.progress}')
--->
<__main__.Wall object at 0x7f4b84e68c50>: 2
#再次“构建”它们
对于正在进行的墙:
wall.build()
对于正在进行的墙:
打印(f'{wall}:{wall.progress}')
--->
: 2
如果我们检查所建列表,我们会发现还剩下两堵墙,但应该有三堵。
为什么会发生这种情况?

构建函数中的问题是,您试图修改正在迭代的同一列表,这导致了这一奇怪问题的发生,请尝试以下操作,您不应该看到该问题。我正在通过copy.copy将列表复制到另一个变量

导入副本
进行中=[]
内置=[]
类墙:
全球在建工程
定义初始化(自):
self.progress=0
正在进行中。追加(自我)
def生成(自):
全球进步
自我进步+=1
#复制一份清单,并对其进行操作
copy\u in\u progress=复制。复制(in\u progress)
如果self.progress==3:
正在复制。删除(自身)
build.append(self)
进行中=复制进行中
墙()
墙()
墙()
打印(正在进行中)
#[, 
#, 
#]
对于正在进行的墙:
打印(f'{wall}:{wall.progress}')
#: 0
#: 0
#: 0
对于正在进行的墙:
wall.build()
wall.build()
对于正在进行的墙:
打印(f'{wall}:{wall.progress}')
#: 2
#: 2
#: 2
对于正在进行的墙:
wall.build()
对于正在进行的墙:
打印(f'{wall}:{wall.progress}')
#什么也没印

遍历列表并在遍历过程中对其进行更改可能会导致一些违反直觉的行为,例如:。通过对您当前所在的元素执行
remove()
,列表将被更改,以便下次通过循环时,下一个元素将超出您认为应该位于的位置,因为通过
remove()
操作,列表被移回一个

在这里,当删除第一个元素时,列表向下移动,使第一个元素变成“ab”。然后在循环的顶部,“下一个”元素是“abc”,因为它现在处于第二个位置,所以“ab”永远不会被测试移除。同样,“再次”和“确认”也不会被删除,因为它们从未经过测试。事实上,“b”和“c”保留在列表中并不是因为它们没有以“a”开头,而是因为列表发生了变化,循环也跳过了它们,所以它们也从未被测试过

如果您迭代原始列表的一个副本或一个片段,这可能会得到您所需要的,但是在任何情况下,如果您在迭代同时更新的内容,请小心

>>> q = ['a', 'ab', 'abc', 'again', 'b', 'a1', 'c', 'a2', 'ack']
>>> for pos in q[:]:
...     if pos.startswith('a'):
...             q.remove(pos)
... 
>>> q
['b', 'c']

您从未将
self
添加到
正在进行的
列表中,为什么您可以删除它?您是对的,对不起。我修好了。你能用注释写代码吗?这很难读。谢谢就我的程序而言,在init内部的进程中添加墙比较容易,但我仍然有另一个与此代码相关的问题。我应该换岗吗?问题?不管怎样,谢谢继续,编辑问题
import copy
in_progress = []
built = []

class Wall:
    global in_progress, built

    def __init__(self):
        self.progress = 0
        in_progress.append(self)

    def build(self):
        global in_progress
        self.progress += 1
        #Make a copy of the list and operate on that
        copy_in_progress = copy.copy(in_progress)
        if self.progress == 3:
            copy_in_progress.remove(self)
            built.append(self)
        in_progress = copy_in_progress

Wall()
Wall()
Wall()

print(in_progress)
#[<__main__.Wall object at 0x108259908>, 
#<__main__.Wall object at 0x108259940>, 
#<__main__.Wall object at 0x1082599e8>]

for wall in in_progress:
    print(f'{wall}: {wall.progress}')

#<__main__.Wall object at 0x108259908>: 0
#<__main__.Wall object at 0x108259940>: 0
#<__main__.Wall object at 0x1082599e8>: 0

for wall in in_progress:
    wall.build()
    wall.build()

for wall in in_progress:
    print(f'{wall}: {wall.progress}')


#<__main__.Wall object at 0x108259908>: 2
#<__main__.Wall object at 0x108259940>: 2
#<__main__.Wall object at 0x1082599e8>: 2
for wall in in_progress:
    wall.build()

for wall in in_progress:
    print(f'{wall}: {wall.progress}')
#Nothing is printed
>>> q = ['a', 'ab', 'abc', 'again', 'b', 'a1', 'c', 'a2', 'ack']
>>> for pos in q:
...     if pos.startswith('a'):
...             q.remove(pos)
... 
>>> q
['ab', 'again', 'b', 'c', 'ack']
>>> q = ['a', 'ab', 'abc', 'again', 'b', 'a1', 'c', 'a2', 'ack']
>>> for pos in q[:]:
...     if pos.startswith('a'):
...             q.remove(pos)
... 
>>> q
['b', 'c']