1.1 Error Occurrence
Errors (and exceptions) are an inevitable part of programming. They pop up when the program encounters unforeseen situations that it can't handle. Python has an exception-handling system that lets you catch and process errors, preventing the program from crashing.
Exceptions usually occur in the following situations:
Syntax Errors:
These errors are caught during the code compilation stage and are related to improper Python grammar. For instance, missing colons or incorrect keywords.
if True:
print("Hello")
Runtime Errors:
These errors happen while the program is running and can be caused by various reasons, such as division by zero, accessing a nonexistent list index, incorrect data type usage, etc.
print(1 / 0) # ZeroDivisionError
Logical Errors:
These occur when the program runs without crashes but delivers incorrect results due to a logic flaw. Logical errors don't trigger exceptions, making them harder to debug.
Logical errors are usually called bugs — essentially, a kind of program functionality oversight. Runtime errors are termed exceptions. For each such error, Python creates a special object (exception) and "throws" it into the program...
1.2 Exception Path
When an exception arises in Python, it travels up the call stack until it is handled. The call stack is a sequence of function calls leading to the exception.
Exception Propagation Mechanism
- Exception Occurrence: When an error happens, Python creates an exception object.
- Finding an Exception Handler: The Python interpreter starts searching for an exception handler in the current code block. If not found, it moves to the next block of code that called the current function.
- Propagating the Exception Up the Stack: This process repeats until a handler is found or the call stack is exhausted.
- Program Termination: If no handler is found, the program terminates and outputs an error message.
Example:
def func_a():
func_b()
def func_b():
func_c()
def func_c():
print(1 / 0) # Exception ZeroDivisionError arises here
func_a()
In this example, the ZeroDivisionError
exception arises in function func_c
and then propagates up the call stack through func_b
and func_a
. If no handler is found, the program will terminate with an error.
1.3 Reading the Log
When a program terminates due to an unhandled exception, Python displays a stack trace (traceback), which helps developers figure out what went wrong. A stack trace contains information about the sequence of function calls leading to the exception and can be analyzed for debugging.
Example of a stack trace
Traceback (most recent call last):
File "example.py", line 10, in
func_a()
File "example.py", line 2, in func_a
func_b()
File "example.py", line 5, in func_b
func_c()
File "example.py", line 8, in func_c
print(1 / 0)
ZeroDivisionError: division by zero
Analyzing a Stack Trace
- Exception Type and Message: The end of the stack trace shows the exception type and message. In
this example, it's
ZeroDivisionError: division by zero
. - Call Sequence: The stack trace shows the sequence of function calls. In our example, the error occurred at
print(1 / 0)
in functionfunc_c
, which was called fromfunc_b
, which in turn was called fromfunc_a
. - Files and Code Lines: Each line in the stack trace indicates the file and line number where the call occurred. This helps quickly locate and fix the error in the code.
Practical Use of Stack Traces
A stack trace is a crucial tool for debugging and analyzing programs. It helps developers understand the cause of the error and find the code section where it occurred. Here are some tips for using stack traces:
- Read from Bottom to Top: Start your analysis with the lowest call in the trace since that's where the exception occurred.
- Check All Calls: Review all the calls in the trace to understand the path the exception took.
- Fix the Code: Use the information from the trace to correct the code and prevent similar errors in the future.
You'll learn more about exceptions in the next lectures.
GO TO FULL VERSION