Python 2.7抛出ValueError:list.remove(x):x不在lis中

2024-06-18 07:45:04 发布

您现在位置:Python中文网/ 问答频道 /正文

每次运行此程序时,都会出现以下错误:

ValueError: list.remove(x): x not in list

我正试图降低一个外星生命,每当它被击中一个螺栓。如果这个外星人的健康状况是<= 0,它也应该被摧毁。同样,螺栓也会被破坏。这是我的代码:

def manage_collide(bolts, aliens):
    # Check if a bolt collides with any alien(s)
    for b in bolts:
        for a in aliens:
            if b['rect'].colliderect(a['rect']):
                for a in aliens:
                    a['health'] -= 1
                    bolts.remove(b)
                    if a['health'] == 0:
                        aliens.remove(a)
    # Return bolts, aliens dictionaries
    return bolts, aliens

ValueError发生在aliens.remove(a)行上。为了澄清,这两个词都是字典列表。

我做错什么了?


Tags: inrect程序forif错误notremove
3条回答

不应从循环的列表中删除项。改为创建副本:

for a in aliens[:]:

以及

for b in bolts[:]:

在列表上循环时修改列表会影响循环:

>>> lst = [1, 2, 3]
>>> for i in lst:
...     print i
...     lst.remove(i)
... 
1
3
>>> lst
[2]

从循环两次的列表中删除项会使事情更加复杂,从而导致值错误:

>>> lst = [1, 2, 3]
>>> for i in lst:
...     for a in lst:
...         print i, a, lst
...         lst.remove(i)
... 
1 1 [1, 2, 3]
1 3 [2, 3]
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: list.remove(x): x not in list

在循环的每个级别创建要修改的列表副本时,可以避免以下问题:

>>> lst = [1, 2, 3]
>>> for i in lst[:]:
...     for i in lst[:]:
...         print i, lst
...         lst.remove(i)
... 
1 [1, 2, 3]
2 [2, 3]
3 [3]

当你发生碰撞时,你只需要移除一次螺栓,而不是在伤害外星人的回路中。以后把外星人分开清理:

def manage_collide(bolts, aliens):
    for b in bolts[:]:
        for a in aliens:
            if b['rect'].colliderect(a['rect']) and a['health'] > 0:
                bolts.remove(b)
                for a in aliens:
                    a['health'] -= 1
    for a in aliens[:]:
        if a['health'] <= 0:
            aliens.remove(a)
    return bolts, aliens

你的代码中有一个错误导致了这种情况。简化后的代码看起来像:

for b in bolts:
  for a in aliens:
    for a in aliens:
      bolts.remove(b)

这导致您对b中的每个条目循环aliens多次。如果b在第一个循环中被删除,那么当它第二次循环时,就会出现错误。

有几件事要解决。首先,改变aliens上的内部循环以使用a以外的内容,因此:

for b in bolts:
  for a in aliens:
    for c in aliens:
      if hit:
        bolts.remove(b)

第二,只从bolts中删除b一次。所以:

for b in bolts:
  for a in aliens:
    should_remove = False
    for c in aliens:
      if hit:
        should_remove = True
    if should_remove:
      bolts.remove(b)

我认为这段代码也有其他问题,但这是导致您的主要问题的原因。马蒂金的职位也可能有帮助。

给螺栓一个“健康”,初始化为1。然后你可以做一个嵌套循环来计算所有的伤害,两个独立的不受尊重的“循环”来移除所有的“死亡”。但是,不要这样做,因为你仍然不想修改你正在循环的列表。复制仍然太复杂。您真正想做的是直接构建一个新的列表,其中只包含仍然“活动”的东西,您可以用列表理解(或者如图所示,用filter)描述地完成这项工作。

# for example
class Alien:
    # ... other stuff
    def damage(self): self.hp -= 1
    def alive(self): return self.hp > 0

# similarly for Bolt

def collide(an_alien, a_bolt):
    # etc.

def handle_collisions(aliens, bolts):
    for a in aliens:
        for b in bolts:
            if collide(a, b):
                a.damage()
                b.damage()

    return list(filter(Alien.alive, aliens)), list(filter(Bolt.alive, bolts))

相关问题 更多 >