I am trying to learn how to animate with tkinter. The code below is an example I was able to build. It creates a small 5x5 map of cubes, then one of them randomly moves around the screen (preferably on the map, but it can wander off).Is this a good way to do it?  Is there a more pythonic, or more efficient way of doing it?from tkinter import *from time import sleepfrom random import randrangeclass alien(object):    def __init__(self):        self.root = Tk()        self.canvas = Canvas(self.root, width=400, height=400)        self.canvas.pack()        self.map = [[1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [1, 0, 0, 1, 0]]        self.x = 0        self.y = 0        for row in range(len(self.map)):            for column in range(len(self.map[row])):                color = green                if self.map[row][column] == 1:                    color = black                                #print(50 * row + 50, 50 * column + 50)                self.canvas.create_rectangle(50 * row , 50 * column , 50 * row + 50, 50 * column + 50,                    outline=color, fill=color)         self.creature = self.canvas.create_rectangle(50 * self.x, 50 * self.y, 50 * self.x + 50, 50 * self.y + 50,            outline=red, fill=red)             self.canvas.pack(fill=BOTH, expand=1)           self.root.after(0, self.animation)        self.root.mainloop()    def animation(self):        while True:            i = randrange(1, 5)            print(i)            if i == 1:                y = -1            elif i == 2:                y = 1            elif i == 3:                x = -1            elif i == 4:                x = 1            sleep(0.025)            print(self.x, self.y)            self.canvas.move(self.creature, self.x, self.y)            self.canvas.update()alien()
Animation with 5x5 map of cubes
python;optimization;animation;tkinter;tk
Here is anoted version of your codefrom tkinter import *from time import sleepfrom random import randrange# lowercase tkinter suggest you are using python3, in this case# inheriting (object) is not needed anymore to create newstyle# classclass alien(object):    def __init__(self):        self.root = Tk()        self.canvas = Canvas(self.root, width=400, height=400)        self.canvas.pack()        self.map = [[1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [1, 0, 0, 1, 0]]        self.x = 0        self.y = 0        for row in range(len(self.map)):            for column in range(len(self.map[row])):                color = green                #since 0 evaluate to False, you can drop '== 1'                if self.map[row][column] == 1:                    color = black                                self.canvas.create_rectangle(50 * row , 50 * column , 50 * row + 50, 50 * column + 50,                    outline=color, fill=color)         self.creature = self.canvas.create_rectangle(50 * self.x, 50 * self.y, 50 * self.x + 50, 50 * self.y + 50,            outline=red, fill=red)        #this call overrides the previous 'canvas.pack'. Remove first.        self.canvas.pack(fill=BOTH, expand=1)           self.root.after(0, self.animation)        self.root.mainloop()    def animation(self):        #see below for further explanations on animations.        while True:            i = randrange(1, 5)            print(i)            #note: randrange ouput from 1 to 5 (included)            #thus i = 5 is not handled in your switch (might be on purpose)            if i == 1:                y = -1            elif i == 2:                y = 1            elif i == 3:                x = -1            elif i == 4:                x = 1            # after you switch, either x or y (or both) are not            # initialized            sleep(0.025)            # self.x and self.y are never updated            print(self.x, self.y)            # move is a relative command (expect delta x,delta y)            # if self.x,self.y is your creature absolute position,            # you might want to use 'coords' on (self.x, self.y)             # or 'move' on (x,y)            # in addition, your *50 factor has disapeared.            self.canvas.move(self.creature, self.x, self.y)            # it is good practice to use 'update_idletasks' instead            # of 'update' to avoid race conditions. By the way            # the use of one of them is seldom required (see below)            self.canvas.update()alien()Regarding how you handle the animation, it could be profitable to run your simulation in the python mainloop. What you does now is to provide your own mainloop (while True: [...] sleep(0.025) [...] canvas.update()). This can work, but will fail as soon as you will want to add interactivity to your application (other widgets, or react to events on canvas). This will not work because the execution path is stuck in alien.animation. The solution there would be to rely on tkinter mainloop and to beg for alien.animation to be repeatedly called.def animation(self):    #while True:  no longer needed        i = randrange(1, 5)        #[...]        elif i == 4:            x = 1        #sleep(0.025) becomes        self.root.after(25, animation)        print(self.x, self.y)        self.canvas.move(self.creature, x*50, y*50)        #self.canvas.update() no longer needed