Exception Handling and Debugging⚓︎
Exception Handling⚓︎
- We have seen plenty of errors in previous chapters when something goes wrong or some input was given erroneously
- For example:
$ ./user_input_int.py
Enter an integer number: abc
Traceback (most recent call last):
File "./user_input_int.py", line 6, in <module>
usr_num = int(usr_ip)
ValueError: invalid literal for int() with base 10: 'abc'
- In such cases, it might be preferred to inform the user on the error and give a chance to correct it
- Python provides the
try-exceptconstruct to achieve this
#!/usr/bin/python3
while True:
try:
usr_num = int(input("Enter an integer number: "))
break
except ValueError:
print("Not an integer, try again")
print("Square of entered number is: {}".format(usr_num * usr_num))
exceptcan be used for particular error (in this caseValueError)
$ ./user_input_exception.py
Enter an integer number: a
Not an integer, try again
Enter an integer number: 1.2
Not an integer, try again
Enter an integer number: 3
Square of entered number is: 9
Further Reading
- Python docs - errors, exception handling and raising exceptions
- Python docs - built-in exceptions
- stackoverflow - exception message capturing
- stackoverflow - avoid bare exceptions
- Python docs - pass statement
Syntax check⚓︎
- Python's command line options can be used for variety of purposes
- Syntax checking is one of them
$ python3 -m py_compile syntax_error.py
File "syntax_error.py", line 3
print "Have a nice day"
^
SyntaxError: Missing parentheses in call to 'print'
- Useful to quickly catch syntax errors like missing
:forif for withetc and()forprintstatements - While this example might be trivial, real world program might have thousands of lines and tougher to find typos
- Python docs - cmdline
pdb⚓︎
- Invoking debugger is another use of
cmdline - Use it instead of using
printall over a program when something goes wrong, plus one can use breakpoints and other features specific to debugging programs
$ python3 -m pdb if_elif_else.py
> /home/learnbyexample/python_programs/if_elif_else.py(3)<module>()
-> num = 45
(Pdb) p num
*** NameError: name 'num' is not defined
(Pdb) n
> /home/learnbyexample/python_programs/if_elif_else.py(6)<module>()
-> if num > 25:
(Pdb) p num
45
(Pdb) l
1 #!/usr/bin/python3
2
3 num = 45
4
5 # only if
6 -> if num > 25:
7 print("Hurray! {} is greater than 25".format(num))
8
9 # if-else
10 if num % 2 == 0:
11 print("{} is an even number".format(num))
(Pdb) q
lprints code around the current statement the debugger is at, useful to visualize the progress of debug effortsexecute current line, steps inside function callsnexecute current line and treats function as single execution stepccontinue execution until next breakpointp variableprint value of variablehlist of commandsh chelp onccommand
qquit the debugger
Further Reading
- Python docs - pdb
- pdb tutorial
- common runtime errors
- common beginner errors as a flowchart
- Common pitfalls
- Python docs - Basic Logging Tutorial
Importing program⚓︎
- One can also
importa program directly in Interpreter to test functions if __name__ == "__main__":construct- code inside that construct will be executed when program is intended to be run - ex: executing the program from command line
- code inside that construct will NOT be executed when program is intended to be imported as module - ex: to use programs's functions
- A good practice is to put all code outside of functions inside a
mainfunction and callmain()inside theif __name__ == "__main__":construct - Note that
__name__and__main__have two underscore characters as prefix and suffix
#!/usr/bin/python3
# ----- function without arguments -----
def greeting():
print("-----------------------------")
print(" Hello World ")
print("-----------------------------")
# ----- function with arguments -----
def sum_two_numbers(num1, num2):
sum = num1 + num2
print("{} + {} = {}".format(num1, num2, sum))
# ----- function with return value -----
def num_square(num):
return num * num
# ----- main -----
def main():
greeting()
sum_two_numbers(3, 4)
my_num = 3
print(num_square(2))
print(num_square(my_num))
if __name__ == "__main__":
main()
- When run as a program
$ ./functions_main.py
-----------------------------
Hello World
-----------------------------
3 + 4 = 7
4
9
- When importing
>>> import functions_main
>>> functions_main.greeting()
-----------------------------
Hello World
-----------------------------
>>> functions_main.num_square()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: num_square() missing 1 required positional argument: 'num'
>>> functions_main.num_square(5)
25
>>> functions_main.main()
-----------------------------
Hello World
-----------------------------
3 + 4 = 7
4
9
Further Reading