Symon
Symon

Reputation: 2220

Reducing menu.add_command() clutter/repeat lines

I would like to do the following (just an example, the real code has more menu's and more add_command's):

editmenu.add_command(label="Cut",state="disabled")
editmenu.add_command(label="Copy",state="disabled")
editmenu.add_command(label="Paste",state="disabled")
editmenu.add_command(label="Delete",state="disabled")

But on fewer lines, In fact, just one line if possible. I have menus that are taking up a considerable amount of space in my program and would like to reduce the clutter. Plus the programmer in me sees a bunch of similar lines and feels there must be a way to reduce them.

I tried the following code to no avail; I obviously got a nameerror because label and state aren't defined...

for labeldic in [{label:"Cut"},{label:"Copy"},{label:"Paste"},{label:"Delete"}]: editmenu.add_command(labeldic+{state:"disabled"})

Thanks in advance for any suggestions!

Upvotes: 2

Views: 128

Answers (1)

Devin Jeanpierre
Devin Jeanpierre

Reputation: 95526

Here's a translation of what you wanted to do:

for labeldic in [{"label":"Cut"},{"label":"Copy"},{"label":"Paste"},{"label":"Delete"}]:
    labeldic.update({"state": "disabled"})
    editmenu.add_command(**labeldic)

There were three problems I fixed.

The first is that dictionary keys need to be quoted if they are strings. If you want a dict mapping the string 'label' to the the string 'cut', you can do it using the dict literal {'label': 'cut'}, or else possibly with the dict() constructor which expands keyword arguments that way: dict(label='cut'). As you discovered, {label: 'cut'} wouldn't work, because it tries to use a variable's value for the key, but there is no such variable.

The second is that you can't merge dictionaries using the + operator. It doesn't work, unfortunately. There is, however, an update method that mutates the dict it's called on. Since it doesn't return a merged dict, it can't be used inline the way you used +.

The third problem is that passing a dict is not the same as passing in keyword arguments. foo(bar='baz') is not the same as foo({'bar':'baz'}), but it is the same as foo(**{'bar':'baz'}). The ** syntax in function calling "unpacks" a dictionary into keyword arguments.

Regardless it's sort of weird style. Here's what I would do instead:

for label in ['Cut', 'Copy', 'Paste', 'Delete']:
    editmenu.add_command(label=label, state='disabled')

Upvotes: 4

Related Questions