Python best practice: try except pass?

Viewed 905

Small question, one for me to just learn best practice more than anything. If there is a better way to do this please critique :)

Basically I have multiple GPIO inputs that correspond to one button press. So for example, if the user presses button 2, I get High values from pin 5, and pin 6.

So in my code, I need to map the High pins to a "button" id.

To do this, I am using a 2D list where the index of the elements will correspond to the "id" of the button.

buttons = [
    [],
    [PIN_5],
    [PIN_5, PIN_6],
    [PIN_6],
    [PIN_6, PIN_19],
    ...
]

I am using a threaded loop to check for pin values, and storing the high state pins in a new list.

So once a button is pressed, a new list will have what pins are high.

pins_high = [PIN_5, PIN_6]

So this is where my best practice question comes in, to map those pins to the button "id" in the mapping list, I am using a try except pass approach

button_pressed = 0
try:
    button_pressed = buttons.index(pins_high)
except ValueError:
    pass

Is this best practice? It seems to me like a nice neat solution, but am I overlooking any possible leaks/effects of using a try/except/pass like this?

Cheers, Jamie

2 Answers

Using a dict is first of all more efficient (look-up time of O(1) as opposed to the list.index's O(n)), and also reduces the need for try/except with the help of the get() method. The "problem" is that dicts' keys need to be hashable - which lists are not. So you will need to convert them to tuples (which are hashable):

buttons = {
    (PIN_5,): 1,
    (PIN_5, PIN_6): 2,
    (PIN_6,): 3,
    (PIN_6, PIN_19): 4
}

And now using the get method you check for a key, and if it is not found, it will return the second default argument:

button_pressed = buttons.get(tuple(pins_high), 0)

Note that this is "order-sensitive" - meaning that [PIN_6, PIN_5] will return 0 and not 2!

no. First thigns first: whenever you have to retrieve a value given a key, just use a dictionary:

buttons = {
    (): 0, 
    (PIN_5,): 1,
    (PIN_5, PIN_6): 2, 
    ...
}  

See that (1) the values can be arbitrary, and no need to do hacks so that the rder of insertion of your combination needs to match the numeric value you need, and (2), search order is arbitrary, O[1], no linear search for each button press, and (3) dictionaries have the .get method that allow you to check for containment without needing to handle exceptions.

Moreover, and a bit more "advanced" - you can use "frozenset" objects for the keys, so you don't depend on button order:

F = frozenset

buttons = {
    F(): 0, 
    F((PIN_5,)): 1,
    F((PIN_5, PIN_6)): 2, 
    ...
}  

...

button_pressed = buttons.get(F(pins_high), 0)
Related