在列表中进行迭代的工作顺序相反,但不能在列表中进行(python/pygame)

在列表中进行迭代的工作顺序相反,但不能在列表中进行(python/pygame),python,pygame,Python,Pygame,我用python编写了这段代码,使用pygame在屏幕上显示对象,然后检测碰撞并在发生碰撞时删除对象 每当发生冲突时,当我将代码编写成这样时,我会得到以下错误: 代码: for i in range(len(asteroids)): asteroidObj = asteroids[i] asteroidObj['rect'] = pg.Rect((asteroidObj['x'],

我用python编写了这段代码,使用pygame在屏幕上显示对象,然后检测碰撞并在发生碰撞时删除对象

每当发生冲突时,当我将代码编写成这样时,我会得到以下错误:

代码:

    for i in range(len(asteroids)):
        asteroidObj = asteroids[i]
        asteroidObj['rect'] = pg.Rect((asteroidObj['x'],
                                       asteroidObj['y'],
                                       asteroidObj['width'],
                                       asteroidObj['height']))
        screen.blit(asteroidObj['surf'], asteroidObj['rect'])
        asteroidObj['x']+= asteroidObj['xChange']
        asteroidObj['y']+= asteroidObj['yChange']
        if asteroidObj['rect'].colliderect(shipObj['rect']):
            del asteroids[i]
错误:

    asteroidObj = asteroids[i]
    IndexError: list index out of range
但是,如果我将for循环更改为:

for i in range(len(asteroids)-1, -1, -1):
代码按预期工作,我不再收到错误


其中一个循环从第0-49项迭代,另一个从第49-0项迭代,所以我不明白为什么一个循环有效,一个循环无效。有人知道为什么会这样吗?

它只能反向工作,因为您正在从列表中删除元素

例如,假设你有50颗小行星,那么你的列表从0到49。小行星
i==48
碰撞,您将其从列表中删除。现在您的列表长度为49(范围从0到48),但是
range(len(asteroids))
已经被计算过了,在下一次迭代中,您将得到
i==49
,但是不再有元素49。当您删除以前的48时,它成为新的48

正如您所想,反向操作是解决问题的一种方法,但我建议避免从列表中间删除元素,因为这是一个O(n)操作。我会这样做:

new_asteroids = []
for asteroidObj in asteroids:
    # Do your stuff here...

    if not asteroidObj['rect'].colliderect(shipObj['rect']):
        new_asteroids.append(asteroidObj)
asteroids = new_asteroids

它只能反向工作,因为您正在从列表中删除元素

例如,假设你有50颗小行星,那么你的列表从0到49。小行星
i==48
碰撞,您将其从列表中删除。现在您的列表长度为49(范围从0到48),但是
range(len(asteroids))
已经被计算过了,在下一次迭代中,您将得到
i==49
,但是不再有元素49。当您删除以前的48时,它成为新的48

正如您所想,反向操作是解决问题的一种方法,但我建议避免从列表中间删除元素,因为这是一个O(n)操作。我会这样做:

new_asteroids = []
for asteroidObj in asteroids:
    # Do your stuff here...

    if not asteroidObj['rect'].colliderect(shipObj['rect']):
        new_asteroids.append(asteroidObj)
asteroids = new_asteroids

因为当你删除第25项时,索引26处的内容现在是索引25处,索引49也不再存在,因此你将在列表的末尾运行。因为如果你按顺序迭代列表,当你删除一个元素时,列表的长度会发生变化(变小),并且由于你的索引一直单调增加,您最终将索引超出范围。请参阅问题的答案,以了解发生了什么。相反地迭代列表可以避免这个问题。因为当您删除项目25时,索引26处的内容现在位于索引25处,索引49也不再存在,所以您将在列表的末尾运行。因为如果您按顺序迭代列表,当您删除一个元素时,列表的长度会发生变化(变小),由于你的指数一直单调增加,你最终会指数超出范围。请参阅问题的答案,以了解发生了什么。以相反的方式迭代列表可以避免此问题。