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-except
construct 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))
except
can 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 with
etc and()
forprint
statements - 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
print
all 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
l
prints code around the current statement the debugger is at, useful to visualize the progress of debug efforts
execute current line, steps inside function callsn
execute current line and treats function as single execution stepc
continue execution until next breakpointp variable
print value of variableh
list of commandsh c
help onc
command
q
quit 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
import
a 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
main
function 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