This is one of my first steps with GUI.  I've tried an implementation of Conway's Game of Life with TkInter.I would appreciate any opinions about my code, especially about the separation of GUI and logic.import Tkinter as tkfrom copy import deepcopyfrom random import randrangedef random_fields(width):        Returns a set of tuples of random integers, eg: set((2,4), (6,1)).    These tuples are meant as coordiantes.    The parameter width is the maximum value of x and y.        fields_alive = width * width // 6    fields = set()    for _ in range(fields_alive):        x = randrange(width)        y = randrange(width)        fields.add((x,y))    return fieldsclass Field(object):     Represents a field in Game of Life.     def __init__(self, x, y):         Constructs a dead field at coords x, y         self.x = x        self.y = y        self.is_alive = False    def __str__(self):        return Field: \n   x: {0}; y: {1}; is_alive: {2}\n.format(self.x, self.y, self.is_alive)    def change(self):         Changes from dead to alive and vice-versa.         if self.is_alive:            self.is_alive = False        else:            self.is_alive = Trueclass GameOfLifeMatrix(object):        Represents a matrix in Game of Life and contains the logic.    The global STARTFIELDS is a dict, with some well known repeating patterns like:    blinker and toad        STARTFIELDS = { blinker: ((2,1), (2,2), (2,3)),                    toad: ((2,2), (3,2), (4,2), (1,3), (2,3), (3,3))                   }    def __init__(self, width = 25, start_fields = random):                 Constructs a new square matrix for Game Of Life.         parameters:        width: integer, the width and height of the matrix        start_fields, you can provide:          - blinker or toad for the well known patterns         - random to create a random matrix         - a set of tuples containing specified alive coordinates                if not self.STARTFIELDS.get(start_fields) is None:            self.start_fields = self.STARTFIELDS[start_fields]        elif start_fields == random:            self.start_fields = random_fields(width)        else:            self.start_fields = start_fields        self.width = width        self.generation = 0        self.matrix = list()        for x in range(width):            row = list()            self.matrix.append(row)            for y in range(width):                field = Field(x, y)                if (x, y) in self.start_fields:                    field.change()                row.append(field)    def _should_change(self, field):         Determines if a given field should be changed according to the rules of the game        if (   field.x == 0            or field.y == 0            or field.x == self.width - 1            or field.y == self.width - 1):            # i.e.: field is at the border -> should not change?            return False        alive_neighbours = 0        for x in range(field.x -1, field.x +2):            for y in range(field.y -1, field.y +2):                if x == field.x and y == field.y:                    # field is not neighbour of itself                    continue                if self.matrix[x][y].is_alive:                    alive_neighbours += 1        if (not field.is_alive) and alive_neighbours == 3:            return True        elif field.is_alive and (alive_neighbours < 2 or alive_neighbours > 3):            return True        else:            return False     def next_generation(self):         Evolves the matrix to the next generation.         self.generation += 1        new_matrix = deepcopy(self.matrix)        for field in self.fields():            if self._should_change(field):                new_matrix[field.x][field.y].change()        self.matrix = new_matrix    def fields(self):         Generator, yields all fields of the matrix.         for row in self.matrix:            for field in row:                yield fieldclass GameOfLifeApp(tk.Frame):     Represents the TkInter-Version of the game     def __init__(self, game, generation_interval_ms = 600, color_alive = #000, color_dead = #fff):                Constructs the TkInter app.        parameters:        game: an object of type GameOfLifeMatrix        generation_interval_ms: integer time in milliseconds to display the next genereation        color_alive and color_dead: TkInter-color-strings for alive and dead fields            default dead: white #fff; default alive: black #000                self.game = game        self.generation_interval_ms = generation_interval_ms        self.color_alive = color_alive        self.color_dead = color_dead        self.widgets = dict()        self.root = tk.Tk()        tk.Frame.__init__(self, self.root)        self.grid()        for field in self.game.fields():            widget = tk.Label(height = 1, width = 2, bg = self.color_dead, relief = ridge)            widget.grid(column = field.x, row = field.y)            if field.is_alive:                widget.configure(bg = self.color_alive)            self.widgets[(field.x, field.y)] = widget        self.root.after(self.generation_interval_ms, self.draw)    def draw(self):         Draws the new generation.         for field in self.game.fields():            if field.is_alive:                self.widgets[(field.x, field.y)].configure(bg = self.color_alive)            else:                self.widgets[(field.x, field.y)].configure(bg = self.color_dead)        self.game.next_generation()        self.root.after(self.generation_interval_ms, self.draw)if __name__ == __main__:    game = GameOfLifeMatrix()    app = GameOfLifeApp(game)    app.mainloop()
Game of Life, separation of logic / GUI
python;game of life;tkinter