Python 全攻略第八章 例外處理 (Sec. 115~119)
Image by Thomas Malyska from Pixabay
例外處理簡介
- Exception handling refers to the way that errors and unexpected events are handled during the execution of a program.
- Exception handling is essential for writing robust and reliable code.
- It enables programmers to handle errors and exceptions in a structured and controlled manner.
- There are 2 approaches(coding style) to handle Exceptions
- LBYL(Look Before You Leap)
- Drawback1: This decreases the readability of codes
- Drawback2: Take a longer time to execute the code
- EAFP(Easier to Ask Forgiveness than Permission) In Python, we do EAFP more.
- Advantage1: Reduce race conditions → Multiple threads to access or change the same object.
- Advantage2: Avoid errors during condition checking and the actual execution.
- EAFP is not perfect. For the following cases, we would perfer LBYL
- For a task that is computationally heavy and time consuming.
- For an important task that is costy to trace back. (執行後無法回溯-例如刪檔)
- LBYL(Look Before You Leap)
- A great article for your reference: LBYL vs EAFP: Preventing or Handling Errors in Python
# LBYL Approach - 先預測錯誤並加以防堵 (if ... else ...)
def safe_divide_1(x: int, y: int):
if y == 0:
print("Divide by 0 attempt detected.")
return None
else:
return x / y
# EAFP Approach - 直接執行,有錯再由異常處理來處理 (try ... except ...)
def safe_divide_2(x: int, y: int):
try:
return x / y
except ZeroDivisionError:
print("Divide by 0 attempt detected.")
return None
# This is not real codes - 僅為示意用途
# LBYL - 預想很多可能出錯的狀況
def save_a_file():
result = save_prefs()
if result == 'error':
print('Preference not saved.')
return
result = save_text()
if result == 'error':
print('Not enough memory.')
return
result = save_format()
if result == 'error':
print('Format not saved.')
return
# EAFP - 程式碼較少,比較簡單
def save_a_file():
try:
save_prefs()
save_text()
save_format()
except:
print('Something went wrong...')
例外處理的語法說明
- Python 官方的 Exception 詳細列表,可參考 這裡
- need to have try & except pair
- As is optional for except
- Except will run if try has an error
- Else and finally are also optional
try:
result = 10 + "10"
except:
print("Something went wrong")
finally:
print(result)
# we can have multiple except sections
try:
f = open("testfile.txt", "r")
f.write("write a test line")
except TypeError:
print("There is a typo")
except OSError:
print("There is an OS Error")
except:
print("Whatever other errors will go here.")
finally:
print("This will run no matter what.")
There is an OS Error
This will run no matter what.
def ask_for_int():
while True:
try:
result = int(input("Enter a number here: "))
except ValueError as ve:
print(ve) # print error message
print("Please try again.")
else:
print("Good job!")
return result
ask_for_int()
常見的錯誤與例外
# These errors are all in builtins module -> print(dir(__builtins__))
# 1 Type error
try:
for i in ["a", "b", "c"]:
print(i ** 2)
except TypeError:
print("We have type error!!")
We have type error!!
# 3 Name error
print(x)
# 4 ResursionError -> stack overflow
def hello():
print("hello")
hello()
hello()
# 5 KeyError(dict, tuple) and 6 IndexError(list) -> LookUpError 的 subclass
lst = [1, 2, 3]
print(lst[10])
try:
a = {1: 'hello', 2: 'how', 3: 'are', 4: 'you'}
print(a[5])
except KeyError:
print("We've got a KeyError")
We've got a KeyError
# 7 Value error 無法把字串換成整數
int(250)
int("hello")
# 8 FileNotFound error
try:
with open("hello.txt") as f:
print(f.read())
except FileNotFoundError:
print("File not found")
File not found
如何自訂例外
- In Python, all exceptions must be instances of class derived from BaseException
- If a function wants to throw and exception, then we use the keyword → raise
# 在程式執行時會發生的 error,我們選擇 RuntimeError 當做 parent class
class NegativeNumberException(RuntimeError):
def __init__(self, age):
super().__init__()
self.age = age
if( age < 0):
print("This is not a valid age!!!")
def enter_age(age):
if age < 0:
raise NegativeNumberException(age)
if age % 2 == 0:
print("Your age is an even number.")
else:
print("Your age is odd.")
例外處理的先後順序
- The order of putting exception codes matters
- It could be affected by the hierarchical structure of exception classes.
try:
lst = [1, 2, 3]
print(lst[4]) # Index Error
except LookupError:
print("There is a look up error")
except IndexError:
print("There is an index error")