简体   繁体   中英

Retrieving functions from dictionary values

all! As a personal project of mine, I'm attempting to convert a dice roll animation in tkinkter from using only if statements to dictionary values instead. I'm essentially doing this:

def draw_dice(*args):
    w,h = 23, 23
    x,y,r = 2,2,5
    c = tk.Canvas(root,width=w,height=h,bg='white')

    dots = {
        'dot0':None,
        'dot1':c.create_oval(x, y, x + r, y + r, fill='black'),
        'dot2':c.create_oval(x + 16, y, (x + 16) + r, y + r, fill='black'),
        'dot3':c.create_oval(x, y + 8, x + r, (y + 8) + r, fill='black'),
        'dot4':c.create_oval(x + 8, (y + 8), (x + 8) + r, (y + 8) + r, fill='black'),
        'dot5':c.create_oval(x + 16, (y + 8), (x + 16) + r, (y + 8) + r, fill='black'),
        'dot6':c.create_oval(x, y + 16, x + r, (y + 16) + r, fill='black'),
        'dot9':c.create_oval(x + 16, y + 18, (x + 16) + r, (y + 16) + r, fill='black')
    }

    for arg in args:
        dots.get(arg)

    return c

The code runs, but the output is not as expected. For the *args passed into the function, select values can be:

'dot0', 'dot1'..., 'dot9' or just simply 'dot1'.

Within another function of mine, I append the returned c (canvas) to a list that will shuffle through the various created dice faces to animate a rolling dice.

But, that's not the problem. The problem is coming from this function. After running the debugger, I've discovered that the values for each key are like this:

'dot0':None, 'dot1':1, 'dot2': 2, etc.

Something odd is going on, but I'm suspicious that I may be using this data structure wrong. Any help would be greatly appreciated!

As it is, the dictionary does not have functions, it has the output of functions that have already been invoked.

At the time the interpreter sees the line

 'dot1':c.create_oval(x, y, x + r, y + r, fill='black')

it actually runs the create_oval method, which returns an auto-incremented integer id for the oval. So, after that 'dot1': 1

if you want it to be a function you could do something like

 'dot1': lambda x, y, r: c.create_oval(x, y, x + r, y + r, fill='black')

The same of all dotX keys. Then, you can call it in your loop by

 for arg in args:
     dots.get(arg)(x, y, r)

You have defined eg dot1 as:

'dot1': c.create_oval(x, y, x + r, y + r, fill='black')

This is evaluated when your dictionary is created. The c.create_oval() function does not return anything, so it returns None . This value is stored in the dictionary.

Presumably you want to defer execution of these calls until you actually call draw_dice() . To do this, you need to make the value of your dictionary items functions. The easiest way of doing this is to use lambda to define a one-line anonymous function:

'dot1': lambda: c.create_oval(x, y, x + r, y + r, fill='black')

And when you iterate through your arguments, call the function:

for arg in args:
     dots[arg]()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM