Bugs drawing with turtle(python) using onkey() and dictionaries
Question: I decided redo this question as per advice I received, This is an assignment
question I have been given for 1st year uni, python coding. I have bugs in my
code and Can't figure out where to fix them. BUG 1 The turtle starts drawing
when program is ran even though pen is up. BUG 2 undefined key such as 's, 7,
tab' trigger space_bar function

COLOURING BOOK

In this task you create a children's colouring game in which given pictures
can be coloured by tracing around a shape and then filling it. The controls
are as follows.

ARROW KEYS - Move the "brush" (turtle cursor) left, right, up or down by a
fixed small amount.

'z' - Undo the last step.

'r', 'g', 'b' - Change the brush colour to red, green or blue, respectively.
(You can define more colours if you like, but we expect at least these three.)

SPACE BAR - Toggle the painting mode. In "move" mode, which is the initial
mode, the "brush" (turtle) moves around the screen without drawing. In "paint"
mode the brush leaves a coloured line as it moves. Most importantly, when the
mode is changed from "paint" to "move", the area traced out by the brush is
filled with colour.

    
    
    from turtle import *
    from functools import partial 
    bgpic("Colour_A_Turkey.gif") # change this to change the picture
    
    #control the accuracy/speed of the drawing 
    step_size =8
    pensize(4)
    penup()
    
    # whenever spacebar is pressed the current state  and next state switch values 
    current_state = penup
    next_state = pendown
    def space_bar():
        global current_state, next_state
        next_state()
        current_state, next_state = next_state, current_state
        #if the current stat is penup fill in with current colour
        if current_state == penup:
            end_fill()
        else:
            begin_fill()
    onkey(space_bar, " ")
    
    # undo do a mistake function
    def mistake():
        undo()
    onkey(mistake, "z")
    
    #using partial function to store the following functions
    #so they can be called  as arguments from a dictionary
    #movement
    strait = partial(fd, step_size)
    reverse = partial(bk, step_size)
    turn_rt = partial(rt, step_size)
    turn_lf = partial(lt, step_size)
    
    #colour
    brow = partial(color, "brown")
    gree = partial(color, "green")
    yell = partial(color, "yellow")
    oran = partial(color, "orange")
    purp = partial(color, "purple")
    red = partial(color, "red")
    blue = partial(color, "blue")
    
    
    #create a dictionary to store all the keys and there abilities 
    key_action = {"b" : blue, "r" : red, "p" : purp, "o" : oran,\
              "y" : yell, "g" : gree, "w" : brow, "Right" : turn_rt , "Up" : strait,\
              "Down" : reverse, "Left" : turn_lf, "z" : undo()}
    
    #when a key in then above dictionary
    #is pressed it's function  is activated
    for pressed_key, activated_key in key_action.items():
        onkey(activated_key, pressed_key)  
    
    #make turtle look for key strokes with predefined function
    listen()
    #finish
    done()
    


Answer: Remember, in Python, _everything is an object and we really mean that_.
Functions are objects too. We can store functions in a dictionary, and in fact
that's exactly what you seem to want to do here.

    
    
    turn_lf = lt(step_size )
    

The key problem here is that you want to store "a function that calls `lt`
with `step_size` as the argument", but here you have just called `lt` with
`step_size` as an argument immediately, and stored the return value.

Arguably the simplest way to get what you want is to use `functools.partial`
to "bind" the `step_size` argument.

    
    
    from functools import partial
    turn_lf = partial(lt, step_size) # `lt` is not called yet.
    
    # Now, later on, we can do
    turn_lf() # and it's just as if we did `lt(step_size)`.
    # So now we can store `turn_lf` in a dict, look it up and call it later, etc.
    
    # Similarly for all the other functions you want to make.
    

(Another problem is that you haven't been consistent with this; if you want
everything to go in one dict, then you need to indicate the bindings for the
`color` function as well. `'brown'` is just a string, after all. Fortunately,
this is just as simple as with the other functions: we just make our
`partial(color, 'brown')`.

As for `"z" : delete`, well - we don't have any arguments to bind to `undo`.
So while we _could_ follow the pattern and write `partial(undo)` (notice, no
more arguments, because we aren't binding anything), it makes much more sense
to just write `undo` directly.

As an aside, we can simplify this:

    
    
    for key in key_action:
        pressed_key = key
        activated_key = key_action[key]
    

To this:

    
    
    for pressed_key, activated_key in key_action.items():
    

