# 1.2.1.3 PCEP-30-02 Practice Test Compendium – Exceptions and debugging

## Exceptions and debugging

01\) An **exception** is an event caused by an execution error which can induce program termination if not properly handled by the programmer. The situation in which the exception is created and propagated is called **raising** the exception.

02\) Python professes its philosophy expressed with the sentence: *It's better to beg for forgiveness than ask for permission.* The recommendation hidden behind these words says that the programmer should **allow the exceptions to occur and handle them properly** instead of persistently avoiding problems and protecting the code from all possible errors with all their might.

03\) To **control** exceptions and to handle them, Python provides a dedicated construction consisting of the `try` and `except` branches.

04\) The `try` block encloses a part of the code that may cause an exception and when it happens, the execution of the block is terminated and the control jumps into the `except` block, which is dedicated to recognizing the problem and handling it. For example, the following snippet prints `PROCEEDING` even though the code provokes division by zero:

```python
try:
    x = 1 / 0
except:
    x = None
print('PROCEEDING')
```

05\) Here is a list of the most common Python exceptions:

* `ZeroDivisionError`: raised by a division in which the divider is **zero** or is indistinguishable from zero (/, //, and %)
* `ValueError`: raised by the use of values that are **inappropriate** in the current context, for example, when a function receives an argument of a proper type, but its value is **unacceptable**, for example, int('')
* `TypeError`: raised by attempts to apply data of a **type** which cannot be accepted in the current context, for example, `int(None)`
* `AttributeError`: raised – among other occasions – when the code tries to activate a **method** that doesn't exist in a certain item, for example, `the_list.apend()` (note the typo!)
* `SyntaxError`: raised when the control reaches a line of code that **violates** Python's grammar, and which has remained undetected until now;
* `NameError`: raised when the code attempts to make use of a **non-existent** (not previously defined) **item**, for example, a variable or a function.

06\) When more than one exception is expected inside the `try` block and these different exceptions require different handling, another syntax is used where there is more than one named `except` branch. The unnamed (anonymous) `except` branch is the **default** one, and is responsible for servicing these exceptions which still need to be handled.

07\) Not more than one `except` branch can be executed.

08\) The default `except` branch – if it exists – must be the last branch.

09\) For example, the following snippet outputs `NAN` when the user enters a string that is not an integer number, `ZERO` when the user enters `0`, and `ERR` in the case of another error:

```python
try:
    print(1 / int(input("Enter a number: ")))
except ValueError:
    print('NAN')
except ZeroDivisionError:
    print('ZERO')
except:
    print('ERR')
```

10\) An error existing in the code is commonly called a **bug**.

11\) The process by which bugs are detected and removed from the code is called **debugging**.

12\) The tool which allows the programmer to run the code in a fully controllable environment is called a **debugger**.

13\) The '**print debugging**' technique is a trivial debugging technique in which the programmer adds some `print()` function invocations which help to trace execution paths and output the values of selected critical variables.

14\) The process in which the code is probed to ensure that it will behave correctly in a production environment is called **testing**. The testing should prove that all execution paths have been executed and caused no errors.

15\) The programming technique in which the tests and test data are created before the code is written or created in parallel with the code is called **unit testing**. It is assumed that every code amendment (even the most trivial) is followed by the execution of all previously defined tests.
