In our last example, the programmer (you) introduced the exception right in the script. But in real life applications, the exception may be caused by a user entering incorrect or unexpected data during run time. And, the user can't necessarily see the code, or understand Python's error types.
The next example program works much like the previous ones, but it lets the user change the value of d — the denominator— by entering data in the terminal instead of modifying the script.
# exceptions_user_division_calc from microbit import * sleep(1000) print("Division Calculations") while True: text = input("Enter numerator n: ") n = float(text) text = input("Enter denominator d: ") d = float(text) q = n / d print("Quotient q: ") print("q = n / d") print(" = ", n, " / ", d) print(" = ", q) print("Try again!") print()
This type of application is explained in detail in Computer - micro:bit Talk [1], leading up to the apps in the Input/Print for Applications [2] page. So, let’s just look at the exceptions that occurred.
Like the previous activity, when you typed 0 and pressed enter, a ZeroDivisionError exception occurred at the q = n / d statement since it cannot give you an answer with d = 0. No surprise here.
Next, when you tried “Hello" in the denominator, a new error occurred—the ValueError. This is different from TypeError we saw previously. In our earlier example that used the terminal, d was defined as an int. Here, d is defined as a float.
So, here the code froze when it tried to execute float(“Hello”). The float function can convert text that represents a value into that value. So, in d = float("5"), the float function receives the text string “5” and returns the value 5. That value gets stored in the variable d.
If a variable named text stores the string “5”, then d = float(text) will also store the value 5 in d. In contrast, d = float(“Hello!”) has non-digits that the float function cannot convert to a number. At that point, the MicroPython runtime raises the ValueError exception.
While developing the app, it’s still a good idea to to display the error and type so that you can attempt to “break” the code with different variations of user input errors.
Your script can selectively address more than one kind of exception with a single action. For example, if you want it to display the “Expected a number.” message for either a TypeError or a ValueError, you could use this:
except (TypeError, ValueError): print("Expected a number.")
The first step to preventing a user from causing an exception is to test as many user mistakes as you can think of. Make sure to record each type of exception that occurred. You will need that list later so that each exception type can be handled properly.
To speed up the process, use the except Exception as e block, and print the exception’s text and type. This will allow you to keep the app running as you test various user errors that cause exceptions. Here is an example.
# exceptions_user_division_calc_try_this.py from microbit import * sleep(1000) print("Division Calculations") while True: try: text = input("Enter numerator n: ") n = float(text) text = input("Enter denominator d: ") d = float(text) q = n / d except Exception as e: print("Exception = ", e) et = type(e) print("Exception type = ", et) else: print("Quotient q: ") print("q = n / d") print(" = ", n, " / ", d) print(" = ", q) finally: print("Try again!") print()
Now that you know what exception types to expect, you can modify your application to handle each one by responding with helpful user prompts. Your customers will thank you one day!
except Exception as e: print("Exception = ", e) et = type(e) print("Exception type = ", et)
...to this:
except (TypeError, ValueError): print("Expected a number.") except ZeroDivisionError: print("Can't divide by zero.")
Links
[1] https://learn.parallax.com/tutorials/robot/cyberbot/computer-microbit-talk
[2] https://learn.parallax.com/tutorials/robot/cyberbot/computer-microbit-talk/inputprint-applications