所以我一直在做一个学校项目,这个函数给我带来了很多麻烦。它从索引 (x, y) 中获取字典中的对象,并将其移动到新索引。每次运行它时我都会收到 RuntimeError,我认为这是因为我在字典中添加了一个新索引,但我不知道如何解决问题。敌人中的敌人具有"跳跃"属性(整数),并且位于索引(xlocation,ylocation)。这是代码;
def moveEnemies(self):
keys = self.enemydict.keys()
for key in keys:
leap = self.enemydict[key].leap
if self.enemydict[key].attacked == False:
self.enemydict[key].counter -= 1
if self.enemydict[key].counter <= 0 and self.enemydict[key].attacked == False:
self.enemydict[key].counter = self.enemydict[key].turncount
for i in range(leap):
option = random.randint(0, 9)
if option == 1:
goingTo = [key[0]+1,key[1]]
elif option == 2:
goingTo = [key[0]+1,key[1]+1]
...
elif option == 8:
goingTo = [key[0]-1,key[1]-1]
else:
goingTo = key
if self.getMapSquare(goingTo[1], goingTo[0]) == '#':
self.genSquare(goingTo[1], goingTo[0])
try:
self.enemydict[(goingTo[0], goingTo[1])] = self.enemydict[key]
self.enemydict[key] = ' '
except: #this fixed a smaller problem, but it just gave the runtimeerror
pass
continue
下面是错误回溯:
Traceback (most recent call last):
File "/home/ubuntu/workspace/cp1-workspace/semester-1 - Python/unit-06 - oop and game/p1-pyzork/not_quite_zork/game.py", line 442, in <module>
gm.mainloop()
File "/home/ubuntu/workspace/cp1-workspace/semester-1 - Python/unit-06 - oop and game/p1-pyzork/not_quite_zork/game.py", line 423, in mainloop
self.moveEnemies()
File "/home/ubuntu/workspace/cp1-workspace/semester-1 - Python/unit-06 - oop and game/p1-pyzork/not_quite_zork/game.py", line 365, in moveEnemies
for key in keys:
RuntimeError: dictionary changed size during iteration
非常感谢任何可以提供帮助的人!
错误消息的意思就是它所说的:您在迭代字典时更改了字典的大小。
这发生在这一行中:
self.enemydict[(goingTo[0], goingTo[1])] = self.enemydict[key]
这会向self.enemydict
添加一个新值,并且它位于循环中,您可以在循环中迭代该字典:
keys = self.enemydict.keys()
for key in keys:
下面是 Python 控制台中的一个简化示例:
>>> d = { 'a': 'A', 'b': 'B' }
>>> d
{'a': 'A', 'b': 'B'}
>>> keys = d.keys()
>>> for k in keys:
... print( k )
... if k == 'a':
... d['c'] = 'C'
...
a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
请注意,即使我们已经将d.keys()
赋值到它自己的变量keys
中,Python 仍然知道keys
与原始字典相关联,因此当我们添加新元素来d
时,它会使迭代无效。
解决此问题的一种简单方法可能是使用list()
将keys()
转换为简单列表。然后,您将遍历该列表而不是原始字典,并且修改字典不会使迭代无效。(当然,迭代不会触及您在这种情况下添加的新元素。下面是一个示例:
>>> d = { 'a': 'A', 'b': 'B' }
>>> for k in list(d.keys()):
... print( k )
... if k == 'a':
... d['c'] = 'C'
...
a
b
>>> d
{'a': 'A', 'b': 'B', 'c': 'C'}
下面是它在代码中的外观。我还将向您展示一个技巧,使代码更简单,更易于阅读。与其一遍又一遍地引用self.enemydict[key]
,不如将其保存在名为enemy
的变量中一次,然后使用它。
因此,循环的第一部分如下所示:
keys = self.enemydict.keys()
for key in keys:
leap = self.enemydict[key].leap
if self.enemydict[key].attacked == False:
self.enemydict[key].counter -= 1
if self.enemydict[key].counter <= 0 and self.enemydict[key].attacked == False:
self.enemydict[key].counter = self.enemydict[key].turncount
它会是这样的:
for key in list(self.enemydict.keys()):
enemy = self.enemydict[key]
leap = enemy.leap
if enemy.attacked == False:
enemy.counter -= 1
if enemy.counter <= 0 and enemy.attacked == False:
enemy.counter = enemy.turncount
在循环的后面有一个地方,你可以从以下位置进行类似的更改:
self.enemydict[(goingTo[0], goingTo[1])] = self.enemydict[key]
self.enemydict[key] = ' '
自:
self.enemydict[(goingTo[0], goingTo[1])] = enemy
self.enemydict[key] = ' '
但请注意,我只更改了这两行中的第一行。我没有将第二行更改为:
enemy = ' '
这不会与原始代码执行相同的操作。而不是在self.enemydict
中更新或添加值,它会更改enemy
变量,因此它不再是对self.enemydict[key]
的引用。
当您执行以下操作时,这不是问题:
enemy.counter = enemy.turncount
因为我们没有更改enemy
变量本身,只更改.counter
属性。enemy
继续引用字典条目。