ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ
Raising your own errors
So far, errors have come from Python: int() raises when it can't convert. Your own
functions can do the same. When a function is given something it can't work with, the
most useful thing it can do is stop and say so clearly. By the end of this lesson your
functions will raise errors with messages that tell the caller exactly what's wrong.
A quiet wrong answer
Here's grade_for from lesson 5.8. A score must be 0 to 100. Predict what it does with
150:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
def grade_for(score):
if score >= 85:
return "A"
elif score >= 70:
return "B"
elif score >= 50:
return "C"
else:
return "F"
print(grade_for(150))Python prints
A
Nothing in the function checks the range. 150 >= 85, so it returns A, quietly.
Python only knows what you tell it; it has no idea a score stops at 100. A typo like 150 for 50 gets an A, the A goes on a report, and nobody notices. A wrong answer that looks right is worse than an error, because an error at least stops the program where the problem is.
raise
To
an error, write raise, then the error type with a message in parentheses. It stops the
function on the spot, like return, but sends an error to the caller instead of a value.
This shorter grade function uses pass and fail:
def grade_for(score):
if score < 0 or score > 100:
raise ValueError("score must be 0-100")
if score >= 50:
return "pass"
return "fail"
print(grade_for(150))In the editor, press Escape then Tab to move on.
The traceback ends with ValueError: score must be 0-100, and the line above it is the
raise line. ValueError is the usual type for "right type, wrong value". In lesson
5.8, grade_for only calculated and main() decided what to print; errors split the
work the same way. The function raises; the caller decides what to do about it.
except ValueError as e gives the error a name, e, and printing e shows its
message:
def grade_for(score):
if score < 0 or score > 100:
raise ValueError("score must be 0-100")
if score >= 50:
return "pass"
return "fail"
for score in [72, 150]:
try:
print(score, grade_for(score))
except ValueError as e:
print("Can't grade", score, "-", e)In the editor, press Escape then Tab to move on.
Add -5 to the list and run it: it's caught the same way.
The message must be inside the error, not the error itself:
finally (lesson 7.2) runs even when the function is leaving with return. Predict:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
def check():
try:
return "try"
finally:
print("finally runs")
print(check())Python prints
finally runs try
return 'try' starts to leave the function, but finally runs first and prints. Then the call hands back 'try', and print shows it.
If you picked try alone, you pictured return skipping finally. It never does.
Your own kind of error
A payment app needs an error that means exactly "not enough money". You can make one with two short lines:
class NotEnoughBalance(Exception):
pass
def pay(balance, amount):
if amount > balance:
raise NotEnoughBalance(f"balance is {balance} birr")
return balance - amount
try:
balance = pay(50, 120)
except NotEnoughBalance as e:
print("Payment failed:", e)In the editor, press Escape then Tab to move on.
Read the first two lines as a recipe: "a new kind of error, called NotEnoughBalance,
based on Exception". That's a
.
class makes a new type; pass (lesson 2.6) says it needs nothing added. How classes
work is a whole module later (Module 10), so for now this is a recipe to copy: change
the name, keep the rest. It behaves like any error: you raise it with a message, and
except NotEnoughBalance catches this problem and no other.
Error types come in families. ZeroDivisionError is a kind of ArithmeticError, which
is a kind of Exception, and except catches the type it names and every kind of it:
try:
print(10 / 0)
except ArithmeticError:
print("A maths problem")In the editor, press Escape then Tab to move on.
NotEnoughBalance is a kind of Exception too; that's what the (Exception) says.
When should a function raise, and when should it return None, like to_int in lesson
7.2? Raise when the call is wrong: a correct program never asks for it, like a score of
150. Return None when "no answer" is a normal result the caller expects, like text
that isn't a number or a name that isn't in the list.
ጥያቄ
pay(500, -20) asks to pay a negative amount. What should pay do?
መልመጃ
withdraw
Write withdraw(balance, amount). Raise ValueError("amount can't be negative")
for a negative amount, and NotEnoughBalance with the balance in its message when
the amount is more than the balance. Otherwise return the new balance. Each test
starts from 500.
100: new balance 400
-20: amount can't be negative
900: balance is 500 birrYour code
class NotEnoughBalance(Exception):
pass
def withdraw(balance, amount):
# Raise for a negative amount or not enough balance; else return the new balance
pass
for amount in [100, -20, 900]:
try:
print(f"{amount}: new balance {withdraw(500, amount)}")
except ValueError as e:
print(f"{amount}: {e}")
except NotEnoughBalance as e:
print(f"{amount}: {e}")In the editor, press Escape then Tab to move on.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
class NotEnoughBalance(Exception):
pass
def withdraw(balance, amount):
if amount < 0:
raise ValueError("amount can't be negative")
if amount > balance:
raise NotEnoughBalance(f"balance is {balance} birr")
return balance - amount
for amount in [100, -20, 900]:
try:
print(f"{amount}: new balance {withdraw(500, amount)}")
except ValueError as e:
print(f"{amount}: {e}")
except NotEnoughBalance as e:
print(f"{amount}: {e}")ዋና ዋና ነጥቦች
- A function given bad input should raise an error, not return a wrong answer quietly.
raise ValueError("message")stops the function and sends the error to the caller;except ValueError as egets the message.finallyruns even when a function returns.class NotEnoughBalance(Exception): passmakes your own error type;exceptalso catches every kind of the type it names.- Raise for calls that are wrong; return
Nonefor "no answer" the caller expects.