121 lines
3.1 KiB
Markdown
121 lines
3.1 KiB
Markdown
# Chapter 10. Files and Exceptions
|
|
|
|
Files operation skipped here. Directly head to Exception
|
|
|
|
## Exceptions
|
|
|
|
* **exceptions** = objects python use to manage errors that arise during a program's execution.
|
|
* When python unsure what to do, exception object is created.
|
|
* If exceptions are handled correctly, program can continue run
|
|
* If don't handle exception, program will halt and show *traceback*
|
|
|
|
Syntax of exception handling: `try-except`
|
|
|
|
* `try` tells python do sth
|
|
* `except` tell python what to do if an exception is raised.
|
|
|
|
### e.g. ZeroDivisionError Exception
|
|
|
|
* Simple error, python will create `ZeroDivisionError` in response to do "Divide by Zero".
|
|
* When you think an error may occur, you can write a `try-except` block to handle exception
|
|
|
|
```python
|
|
try:
|
|
print(5/0)
|
|
except ZeroDivisionError:
|
|
print("You can't divide by zero!")
|
|
```
|
|
|
|
If more code followed `try-except` block, the program would continue running. e.g. as shown below
|
|
|
|
### Using Exceptions to Prevent Crashes
|
|
|
|
Handling errors correctly is important when the program has more work to do after the error occurs.
|
|
|
|
```python
|
|
print("Give me two numbers, and I'll divide them.")
|
|
print("Enter 'q' to quit.")
|
|
|
|
while True:
|
|
first_number = input("\nFirst number: ")
|
|
if first_number == 'q':
|
|
break
|
|
second_number = input("Second number: ")
|
|
if second_number == 'q':
|
|
break
|
|
|
|
answer = int(first_number) / int(second_number)
|
|
print(answer)
|
|
```
|
|
|
|
This function ask for numbers and will calculate division. To properly cover potential failure, use `try-except-else` block
|
|
|
|
* `try` block: Python attempts to run code
|
|
* `except` block: catch possible error
|
|
* `else` block: if division operation is successful, carry on!
|
|
|
|
Hence, program can be more robust
|
|
|
|
```python
|
|
try:
|
|
answer = int(first_number) / int(second_number)
|
|
except ZeroDivisionError:
|
|
print("You can't divide by 0!")
|
|
else:
|
|
print(answer)
|
|
```
|
|
|
|
### Handling FileNotFoundError Exception
|
|
|
|
```python
|
|
filename = 'alice.txt'
|
|
|
|
with open(filename, encoding='utf-8') as f:
|
|
contents = f.read()
|
|
```
|
|
|
|
If python cannot find `alice.txt`, it will raise halt, and show traceback
|
|
|
|
```
|
|
Traceback (most recent call last):
|
|
File "alice.py", line 6, in <module>
|
|
with open(filename, encoding='utf-8') as f:
|
|
FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
|
|
```
|
|
|
|
After changing python code to
|
|
|
|
```python
|
|
filename = 'alice.txt'
|
|
|
|
try:
|
|
with open(filename, encoding='utf-8') as f:
|
|
contents = f.read()
|
|
except FileNotFoundError:
|
|
print(f"Sorry, the file {filename} does not exist")
|
|
```
|
|
|
|
Python will show "Sorry, the file alice.txt does not exist"
|
|
|
|
### Failing Silently
|
|
|
|
If you want the program to fail silently and carry on, use `pass` to tell Python to do nothing, and skip the try-except-else blocks
|
|
|
|
```python
|
|
def count_words(filename):
|
|
"""Count the approximate number of words in a file."""
|
|
try:
|
|
--snip--
|
|
except FileNotFoundError:
|
|
pass
|
|
else:
|
|
--snip--
|
|
|
|
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
|
|
for filename in filenames:
|
|
count_words(filename)
|
|
```
|
|
|
|
## Storing Data
|
|
|
|
`json.dump()` & `json.load` |