【问题标题】:what does it mean if I get an IndexError but in different places after I run the program different times?如果我在不同时间运行程序后在不同的地方得到一个 IndexError 是什么意思?
【发布时间】:2020-05-14 18:18:06
【问题描述】:

我正在尝试为我自己的自我开发项目创建 John Conway 的生活游戏。 我遇到的一般问题是让动画在 GUI 上可视化,现在我收到的错误消息如下:

Exception in Tkinter callback
Traceback (most recent call last):
  File "D:\Software\Python\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "gameoflife.py", line 70, in one_cycle
    apply_rules()
  File "gameoflife.py", line 56, in apply_rules
    updated_grid[row][column] = 0
IndexError: list index out of range

但是,如果我第二次运行它,我会在最初所说的错误所在的下面的不同行上得到同样的错误。我知道实际的错误是告诉我我试图访问的索引不在列表中,但我不明白为什么它会出现在下面的行中,就好像前一行已被更正一样。我的代码如下:

from tkinter import *
from random import *
import time
import numpy as np

PIXEL_SIZE = 10
ROW = 910
COLUMN = 700
grid = []
updated_grid = [[]]

def create_grid():
    for row in range(0, ROW):
        grid2 = []
        for column in range(0, COLUMN):
            grid2.append(randint(0, 1))
        grid.append(grid2)


def draw_grid():
    for row in range(0, ROW):
        for column in range(0, COLUMN):
            if grid[row][column] == 1:
                x0 = row*PIXEL_SIZE
                y0 = column*PIXEL_SIZE
                x1 = x0+PIXEL_SIZE
                y1 = y0+PIXEL_SIZE
                canvas.create_rectangle(x0, y0, x1, y1, fill='red')


def apply_rules():
    for row in range(1, ROW - 1):
        for column in range(1, COLUMN - 1):
            neighbours_count = 0
            # will count the neighbours for each cell
            neighbours_count += grid[row-1][column-1] # top left
            neighbours_count += grid[row][column-1] # top center
            neighbours_count += grid[row+1][column-1] # top right

            neighbours_count += grid[row-1][column] # middle left
            neighbours_count += grid[row+1][column] # middle right

            neighbours_count += grid[row-1][column+1] # bottom left
            neighbours_count += grid[row][column+1] # bottom center
            neighbours_count += grid[row+1][column+1] # bottom right

            # Game Of Life rules:

            # alive cell rules
            if grid[row][column] == 1:
                if neighbours_count < 2: # rule 1 any live cell with fewer than two live neighbours dies, as if by underpopulation
                    updated_grid[row][column] = 0
                elif neighbours_count == 2 | neighbours_count == 3: # rule 2 any live cell with two or three live neighbours lives on to the next generation
                    updated_grid[row][column] = 1
                elif neighbours_count > 3 & neighbours_count <= 8: # rule 3 any live cell with more than three live neighbours dies, as if by overpopulation
                    updated_grid[row][column] = 0
                else:
                    updated_grid[row][column] = 0
            elif grid[row][column] == 0: # dead cells rule 4 any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
                if neighbours_count == 3:
                    updated_grid[row][column] = 1
                else:
                    updated_grid[row][column] = 0
    for row in range(0, ROW):
        for column in range(0, COLUMN):
            grid[row][column] = updated_grid[row][column]


def one_cycle():
    apply_rules()
    draw_grid()
    window.after(1, one_cycle)


window = Tk() # creates the window for the game
window.title('Game Of Life Python') # is the game title written on the window
canvas_frame = Frame(window) # creates a frame on the window to hold the canvas
game_title = Frame(window) # creates a frame on the window to display the game title (which will be a label)
start_button = Button(window, text='Start Game', command=one_cycle) # creates a button which will be used to start the game
canvas = Canvas(canvas_frame, width=ROW, height=COLUMN, background='black') # creates the canvas used to the draw the game of life
game_title_label = Label(game_title, text='Game Of Life', font='Helvetica 20 bold', fg='grey') # creates the label for the game title which will be placed in a frame

canvas.grid(row=0, column=0) # places the canvas onto the canvas_frame
canvas_frame.grid(row=1, column=1) # places the canvas_frame onto the window
game_title_label.grid(rowspan=2, column=0) # places the title of the game onto the game_title frame
game_title.grid(row=0, columnspan=2) # places the frame for the game title onto the window
start_button.grid(rowspan=2, column=1) # places the start onto the window


create_grid()
window.mainloop()

任何帮助纠正此错误将不胜感激,谢谢。

【问题讨论】:

  • 您需要预先分配updated_grid,否则通过索引访问其内容将无效,因为不存在。
  • 需要像grid一样分配。
  • 我建议您更改create_grid 以创建一个新网格并将其返回,而不是附加到全局变量。然后你可以同时调用gridupdated_grid
  • @Barmar 谢谢你们的帮助,你们能不能让我明白你的意思?

标签: python python-3.x animation canvas tkinter


【解决方案1】:

你从来没有填写updated_grid,所以你不能分配给它的元素。

您应该在程序启动时创建两个网格。

def create_grid(ROW, COLUMN):
    grid = []
    for row in range(0, ROW):
        grid2 = []
        for column in range(0, COLUMN):
            grid2.append(randint(0, 1))
        grid.append(grid2)
    return grid

grid = create_grid(ROW, COLUMN)
updated_grid = create_grid(ROW, COLUMN)

【讨论】:

  • 感谢帮助它摆脱了索引错误但运行异常,所以现在我必须弄清楚,再次感谢
【解决方案2】:

最简单的解决方案是复制现有网格并继续使用该网格:

import copy

def apply_rules():
    global grid
    updated_grid = copy.deepcopy(grid)
    # the rest of the function here, except the copying back again

    # This is all that's needed to 'copy' it back again:
    grid = updated_grid

这样,您从网格的副本开始:(copy.deepcopy(grid)) 并像您一样覆盖元素:(例如。updated_grid[row][column] = 0) 最后处理旧网格并将新网格保留在一行中: (grid = updated_grid) 引用计数的魔力。

这是double buffering 的一种形式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 2016-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多