Exceptions
Raise
Signaling Errors
Your validation function checks if age is negative. You need to signal "this is
wrong" to the caller. raise creates and throws an exception. The caller must
handle it or let it propagate up.
Raise for invalid input
Signal that input doesn't meet requirements.
# Raising exceptions on invalid input
def main():
# Raise on invalid input
def check_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
if age > 150:
raise ValueError("Age is unrealistic")
return age
print("Age validation:")
# Valid age
try:
result = check_age(25)
print(f" Age {result}: Valid")
except ValueError as e:
print(f" Error: {e}")
# Invalid age
try:
result = check_age(-5)
print(f" Age {result}: Valid")
except ValueError as e:
print(f" Error: {e}")
# Raise on division by zero
def safe_divide(a, b):
if b == 0:
raise ZeroDivisionError("Cannot divide by zero")
return a / b
print("\nDivision:")
try:
result = safe_divide(10, 2)
print(f" 10 / 2 = {result}")
except ZeroDivisionError as e:
print(f" Error: {e}")
try:
result = safe_divide(10, 0)
print(f" 10 / 0 = {result}")
except ZeroDivisionError as e:
print(f" Error: {e}")
# Validate string input
def validate_username(username):
if not username:
raise ValueError("Username cannot be empty")
if len(username) < 3:
raise ValueError("Username must be at least 3 characters")
if not username.isalnum():
raise ValueError("Username must be alphanumeric")
return username
print("\nUsername validation:")
usernames = ["alice", "ab", "", "user@123"]
for name in usernames:
try:
valid = validate_username(name)
print(f" '{name}': OK")
except ValueError as e:
print(f" '{name}': {e}")
if __name__ == "__main__":
main()
# Raising exceptions on invalid input
def main():
# Raise on invalid input
def check_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
if age > 150:
raise ValueError("Age is unrealistic")
return age
print("Age validation:")
# Valid age
try:
result = check_age(25)
print(f" Age {result}: Valid")
except ValueError as e:
print(f" Error: {e}")
# Invalid age
try:
result = check_age(-5)
print(f" Age {result}: Valid")
except ValueError as e:
print(f" Error: {e}")
# Raise on division by zero
def safe_divide(a, b):
if b == 0:
raise ZeroDivisionError("Cannot divide by zero")
return a / b
print("\nDivision:")
try:
result = safe_divide(10, 2)
print(f" 10 / 2 = {result}")
except ZeroDivisionError as e:
print(f" Error: {e}")
try:
result = safe_divide(10, 0)
print(f" 10 / 0 = {result}")
except ZeroDivisionError as e:
print(f" Error: {e}")
# Validate string input
def validate_username(username):
if not username:
raise ValueError("Username cannot be empty")
if len(username) < 3:
raise ValueError("Username must be at least 3 characters")
if not username.isalnum():
raise ValueError("Username must be alphanumeric")
return username
print("\nUsername validation:")
usernames = ["bob", ""]
for name in usernames:
try:
valid = validate_username(name)
print(f" '{name}': OK")
except ValueError as e:
print(f" '{name}': {e}")
if __name__ == "__main__":
main()
# Raising exceptions on invalid input
def main():
# Raise on invalid input
def check_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
if age > 150:
raise ValueError("Age is unrealistic")
return age
print("Age validation:")
# Valid age
try:
result = check_age(25)
print(f" Age {result}: Valid")
except ValueError as e:
print(f" Error: {e}")
# Invalid age
try:
result = check_age(-5)
print(f" Age {result}: Valid")
except ValueError as e:
print(f" Error: {e}")
# Raise on division by zero
def safe_divide(a, b):
if b == 0:
raise ZeroDivisionError("Cannot divide by zero")
return a / b
print("\nDivision:")
try:
result = safe_divide(10, 2)
print(f" 10 / 2 = {result}")
except ZeroDivisionError as e:
print(f" Error: {e}")
try:
result = safe_divide(10, 0)
print(f" 10 / 0 = {result}")
except ZeroDivisionError as e:
print(f" Error: {e}")
# Validate string input
def validate_username(username):
if not username:
raise ValueError("Username cannot be empty")
if len(username) < 3:
raise ValueError("Username must be at least 3 characters")
if not username.isalnum():
raise ValueError("Username must be alphanumeric")
return username
print("\nUsername validation:")
usernames = ["user1", "a", "test!", "valid123"]
for name in usernames:
try:
valid = validate_username(name)
print(f" '{name}': OK")
except ValueError as e:
print(f" '{name}': {e}")
if __name__ == "__main__":
main()
def main(): # Raise on invalid input
3def main():4 # Raise on invalid input5 def check_age(age):6 if age < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:9 raise ValueError("Age is unrealistic")10 return age11 12 print("Age validation:")outputAge validation:def check_age(age):
pass 1 of 24# Raise on invalid input5def check_age(age25):6 if age < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:9 raise ValueError("Age is unrealistic")10 return age25result ← 25
15try:16 result→ 25 = check_age(25)17 print(f" Age {result25}: Valid")18except ValueError as e:output Age 25: Validdef check_age(age):
pass 2 of 24# Raise on invalid input5def check_age(age-5):6 if age < 0:7 raise ValueError("Age cannot be negative")if age < 0:
5def check_age(age):6 if age-5 < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:except ValueError as e:
24 print(f" Age {result}: Valid")25except ValueError as e:26 print(f" Error: {eAge cannot be negative}")2728#@help h1output Error: Age cannot be negative Error: Age cannot be negativeprint(" Division:")
40print("\nDivision:")output Division:def safe_divide(a, b):
pass 1 of 234# Raise on division by zero35def safe_divide(a10, b2):36 if b == 0:37 raise ZeroDivisionError("Cannot divide by zero")38 return a10 / b2result ← 5.0
42try:43 result→ 5.0 = safe_divide(10, 2)44 print(f" 10 / 2 = {result5.0}")45except ZeroDivisionError as e:output 10 / 2 = 5.0def safe_divide(a, b):
pass 2 of 234# Raise on division by zero35def safe_divide(a10, b0):36 if b == 0:37 raise ZeroDivisionError("Cannot divide by zero")if b == 0:
35def safe_divide(a, b):36 if b0 == 0:37 raise ZeroDivisionError("Cannot divide by zero")38 return a / bexcept ZeroDivisionError as e:
50 print(f" 10 / 0 = {result}")51except ZeroDivisionError as e:52 print(f" Error: {eCannot divide by zero}")5354# Validate string inputoutput Error: Cannot divide by zero Error: Cannot divide by zerousernames ← ['alice', 'ab', '', 'user@123']
64print("\nUsername validation:")6566usernames→ ['alice', 'ab', '', 'user@123'] = ["alice", "ab", "", "user@123"]67#@usernames=["bob", ""], ["user1", "a", "test!", "valid123"]output Username validation:for name in usernames:
pass 1 of 469for namealice in usernames['alice', 'ab', '', 'user@123']:70 try:71 valid = validate_username(name)All 4 passes — pass 1 is the card above pass nameusername1 alice — 2 ab ab 3 (empty) (empty) 4 user@123 user@123 try:
pass 1 of 469for name in usernames:70 try:71 valid = validate_username(namealice)72 print(f" '{name}': OK")All 4 passes — pass 1 is the card above pass nameusername1 alice — 2 ab ab 3 (empty) (empty) 4 user@123 user@123 def validate_username(username):
pass 1 of 454# Validate string input55def validate_username(usernamealice):56 if not username:57 raise ValueError("Username cannot be empty")58 if len(username) < 3:59 raise ValueError("Username must be at least 3 characters")60 if not username.isalnum():61 raise ValueError("Username must be alphanumeric")62 return usernamealiceAll 4 passes — pass 1 is the card above pass username1 alice 2 ab 3 (empty) 4 user@123 valid ← alice
70try:71 valid→ alice = validate_username(namealice)72 print(f" '{namealice}': OK")73except ValueError as e:output 'alice': OKif len(username) < 3:
57 raise ValueError("Username cannot be empty")58if len(usernameab) < 3:59 raise ValueError("Username must be at least 3 characters")60if not username.isalnum():except ValueError as e:
pass 1 of 372 print(f" '{name}': OK")73except ValueError as e:74 print(f" '{nameab}': {eUsername must be at least 3 characters}")output 'ab': Username must be at least 3 characters 'ab': Username must be at least 3 charactersAll 3 passes — pass 1 is the card above pass nameeusername1 ab Username must be at least 3 characters (empty) 2 (empty) Username cannot be empty user@123 3 user@123 Username must be alphanumeric — if not username:
55def validate_username(username):56 if not username(empty):57 raise ValueError("Username cannot be empty")58 if len(username) < 3:if not username.isalnum():
59 raise ValueError("Username must be at least 3 characters")60if not usernameuser@123.isalnum():61 raise ValueError("Username must be alphanumeric")62return usernamemain()
76if __name__ == "__main__":77 main()
def main(): # Raise on invalid input
3def main():4 # Raise on invalid input5 def check_age(age):6 if age < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:9 raise ValueError("Age is unrealistic")10 return age11 12 print("Age validation:")outputAge validation:def check_age(age):
pass 1 of 24# Raise on invalid input5def check_age(age25):6 if age < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:9 raise ValueError("Age is unrealistic")10 return age25result ← 25
15try:16 result→ 25 = check_age(25)17 print(f" Age {result25}: Valid")18except ValueError as e:output Age 25: Validdef check_age(age):
pass 2 of 24# Raise on invalid input5def check_age(age-5):6 if age < 0:7 raise ValueError("Age cannot be negative")if age < 0:
5def check_age(age):6 if age-5 < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:except ValueError as e:
24 print(f" Age {result}: Valid")25except ValueError as e:26 print(f" Error: {eAge cannot be negative}")27output Error: Age cannot be negative Error: Age cannot be negativeprint(" Division:")
35print("\nDivision:")output Division:def safe_divide(a, b):
pass 1 of 229# Raise on division by zero30def safe_divide(a10, b2):31 if b == 0:32 raise ZeroDivisionError("Cannot divide by zero")33 return a10 / b2result ← 5.0
37try:38 result→ 5.0 = safe_divide(10, 2)39 print(f" 10 / 2 = {result5.0}")40except ZeroDivisionError as e:output 10 / 2 = 5.0def safe_divide(a, b):
pass 2 of 229# Raise on division by zero30def safe_divide(a10, b0):31 if b == 0:32 raise ZeroDivisionError("Cannot divide by zero")if b == 0:
30def safe_divide(a, b):31 if b0 == 0:32 raise ZeroDivisionError("Cannot divide by zero")33 return a / bexcept ZeroDivisionError as e:
45 print(f" 10 / 0 = {result}")46except ZeroDivisionError as e:47 print(f" Error: {eCannot divide by zero}")4849# Validate string inputoutput Error: Cannot divide by zero Error: Cannot divide by zerousernames ← ['bob', '']
59print("\nUsername validation:")6061usernames→ ['bob', ''] = ["bob", ""]output Username validation:for name in usernames:
pass 1 of 263for namebob in usernames['bob', '']:64 try:65 valid = validate_username(name)try:
pass 1 of 263for name in usernames:64 try:65 valid = validate_username(namebob)66 print(f" '{name}': OK")def validate_username(username):
pass 1 of 249# Validate string input50def validate_username(usernamebob):51 if not username:52 raise ValueError("Username cannot be empty")53 if len(username) < 3:54 raise ValueError("Username must be at least 3 characters")55 if not username.isalnum():56 raise ValueError("Username must be alphanumeric")57 return usernamebobvalid ← bob
64try:65 valid→ bob = validate_username(namebob)66 print(f" '{namebob}': OK")67except ValueError as e:output 'bob': OKfor name in usernames:
pass 2 of 263for name(empty) in usernames['bob', '']:64 try:65 valid = validate_username(name)try:
pass 2 of 263for name in usernames:64 try:65 valid = validate_username(name(empty))66 print(f" '{name}': OK")def validate_username(username):
pass 2 of 249# Validate string input50def validate_username(username(empty)):51 if not username:52 raise ValueError("Username cannot be empty")if not username:
50def validate_username(username):51 if not username(empty):52 raise ValueError("Username cannot be empty")53 if len(username) < 3:except ValueError as e:
66 print(f" '{name}': OK")67except ValueError as e:68 print(f" '{name(empty)}': {eUsername cannot be empty}")output '': Username cannot be empty '': Username cannot be emptymain()
70if __name__ == "__main__":71 main()
def main(): # Raise on invalid input
3def main():4 # Raise on invalid input5 def check_age(age):6 if age < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:9 raise ValueError("Age is unrealistic")10 return age11 12 print("Age validation:")outputAge validation:def check_age(age):
pass 1 of 24# Raise on invalid input5def check_age(age25):6 if age < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:9 raise ValueError("Age is unrealistic")10 return age25result ← 25
15try:16 result→ 25 = check_age(25)17 print(f" Age {result25}: Valid")18except ValueError as e:output Age 25: Validdef check_age(age):
pass 2 of 24# Raise on invalid input5def check_age(age-5):6 if age < 0:7 raise ValueError("Age cannot be negative")if age < 0:
5def check_age(age):6 if age-5 < 0:7 raise ValueError("Age cannot be negative")8 if age > 150:except ValueError as e:
24 print(f" Age {result}: Valid")25except ValueError as e:26 print(f" Error: {eAge cannot be negative}")27output Error: Age cannot be negative Error: Age cannot be negativeprint(" Division:")
35print("\nDivision:")output Division:def safe_divide(a, b):
pass 1 of 229# Raise on division by zero30def safe_divide(a10, b2):31 if b == 0:32 raise ZeroDivisionError("Cannot divide by zero")33 return a10 / b2result ← 5.0
37try:38 result→ 5.0 = safe_divide(10, 2)39 print(f" 10 / 2 = {result5.0}")40except ZeroDivisionError as e:output 10 / 2 = 5.0def safe_divide(a, b):
pass 2 of 229# Raise on division by zero30def safe_divide(a10, b0):31 if b == 0:32 raise ZeroDivisionError("Cannot divide by zero")if b == 0:
30def safe_divide(a, b):31 if b0 == 0:32 raise ZeroDivisionError("Cannot divide by zero")33 return a / bexcept ZeroDivisionError as e:
45 print(f" 10 / 0 = {result}")46except ZeroDivisionError as e:47 print(f" Error: {eCannot divide by zero}")4849# Validate string inputoutput Error: Cannot divide by zero Error: Cannot divide by zerousernames ← ['user1', 'a', 'test!', 'valid123']
59print("\nUsername validation:")6061usernames→ ['user1', 'a', 'test!', 'valid123'] = ["user1", "a", "test!", "valid123"]output Username validation:for name in usernames:
pass 1 of 463for nameuser1 in usernames['user1', 'a', 'test!', 'valid123']:64 try:65 valid = validate_username(name)All 4 passes — pass 1 is the card above pass nameusernamee1 user1 — — 2 a a Username must be at least 3 characters 3 test! test! Username must be alphanumeric 4 valid123 — — try:
pass 1 of 463for name in usernames:64 try:65 valid = validate_username(nameuser1)66 print(f" '{name}': OK")All 4 passes — pass 1 is the card above pass nameusernamee1 user1 — — 2 a a Username must be at least 3 characters 3 test! test! Username must be alphanumeric 4 valid123 — — def validate_username(username):
pass 1 of 449# Validate string input50def validate_username(usernameuser1):51 if not username:52 raise ValueError("Username cannot be empty")53 if len(username) < 3:54 raise ValueError("Username must be at least 3 characters")55 if not username.isalnum():56 raise ValueError("Username must be alphanumeric")57 return usernameuser1All 4 passes — pass 1 is the card above pass usernamenamee1 user1 — — 2 a a Username must be at least 3 characters 3 test! test! Username must be alphanumeric 4 valid123 — — valid ← user1
64try:65 valid→ user1 = validate_username(nameuser1)66 print(f" '{nameuser1}': OK")67except ValueError as e:output 'user1': OKif len(username) < 3:
52 raise ValueError("Username cannot be empty")53if len(usernamea) < 3:54 raise ValueError("Username must be at least 3 characters")55if not username.isalnum():except ValueError as e:
pass 1 of 266 print(f" '{name}': OK")67except ValueError as e:68 print(f" '{namea}': {eUsername must be at least 3 characters}")output 'a': Username must be at least 3 characters 'a': Username must be at least 3 charactersif not username.isalnum():
54 raise ValueError("Username must be at least 3 characters")55if not usernametest!.isalnum():56 raise ValueError("Username must be alphanumeric")57return usernameexcept ValueError as e:
pass 2 of 266 print(f" '{name}': OK")67except ValueError as e:68 print(f" '{nametest!}': {eUsername must be alphanumeric}")output 'test!': Username must be alphanumeric 'test!': Username must be alphanumericvalid ← valid123
64try:65 valid→ valid123 = validate_username(namevalid123)66 print(f" '{namevalid123}': OK")67except ValueError as e:output 'valid123': OKmain()
70if __name__ == "__main__":71 main()
raise ValueError("message") stops execution and signals error to caller.
Exception propagation
Exceptions bubble up until caught.
# Exception propagation
def main():
# Exception propagates through call stack
def level3():
print(" level3: About to raise")
raise RuntimeError("Error in level3")
def level2():
print(" level2: Calling level3")
level3()
print(" level2: This won't print")
def level1():
print("level1: Calling level2")
level2()
print("level1: This won't print")
print("Propagation demo:\n")
try:
level1()
except RuntimeError as e:
print(f"\nCaught in main: {e}")
# Function that lets exception propagate
def read_config(key):
config = {"host": "localhost", "port": 8080}
# KeyError propagates if key missing
return config[key]
def get_server_url():
host = read_config("host")
port = read_config("port")
return f"http://{host}:{port}"
print("\nConfig reading:")
try:
url = get_server_url()
print(f" URL: {url}")
except KeyError as e:
print(f" Missing config key: {e}")
try:
timeout = read_config("timeout") # Missing key
print(f" Timeout: {timeout}")
except KeyError as e:
print(f" Missing config key: {e}")
# Catch at different levels
def process_data(data):
if not data:
raise ValueError("Data is empty")
return data.upper()
def transform(data):
# Let exception propagate
return process_data(data)
def handle_request(data):
try:
# Catch here
result = transform(data)
return f"Success: {result}"
except ValueError as e:
return f"Error: {e}"
print("\nRequest handling:")
print(f" {handle_request('hello')}")
print(f" {handle_request('')}")
# Chain of operations
def step1(value):
if value < 0:
raise ValueError("Step1: Value must be positive")
return value * 2
def step2(value):
if value > 100:
raise ValueError("Step2: Value too large")
return value + 10
def step3(value):
if value % 2 != 0:
raise ValueError("Step3: Value must be even")
return value / 2
def pipeline(value):
v1 = step1(value)
v2 = step2(v1)
v3 = step3(v2)
return v3
print("\nPipeline processing:")
test_values = [10, -5, 50]
for val in test_values:
try:
result = pipeline(val)
print(f" {val} → {result}")
except ValueError as e:
print(f" {val} → Failed: {e}")
if __name__ == "__main__":
main()
# Exception propagation
def main():
# Exception propagates through call stack
def level3():
print(" level3: About to raise")
raise RuntimeError("Error in level3")
def level2():
print(" level2: Calling level3")
level3()
print(" level2: This won't print")
def level1():
print("level1: Calling level2")
level2()
print("level1: This won't print")
print("Propagation demo:\n")
try:
level1()
except RuntimeError as e:
print(f"\nCaught in main: {e}")
# Function that lets exception propagate
def read_config(key):
config = {"host": "localhost", "port": 8080}
# KeyError propagates if key missing
return config[key]
def get_server_url():
host = read_config("host")
port = read_config("port")
return f"http://{host}:{port}"
print("\nConfig reading:")
try:
url = get_server_url()
print(f" URL: {url}")
except KeyError as e:
print(f" Missing config key: {e}")
try:
timeout = read_config("timeout") # Missing key
print(f" Timeout: {timeout}")
except KeyError as e:
print(f" Missing config key: {e}")
# Catch at different levels
def process_data(data):
if not data:
raise ValueError("Data is empty")
return data.upper()
def transform(data):
# Let exception propagate
return process_data(data)
def handle_request(data):
try:
# Catch here
result = transform(data)
return f"Success: {result}"
except ValueError as e:
return f"Error: {e}"
print("\nRequest handling:")
print(f" {handle_request('hello')}")
print(f" {handle_request('')}")
# Chain of operations
def step1(value):
if value < 0:
raise ValueError("Step1: Value must be positive")
return value * 2
def step2(value):
if value > 100:
raise ValueError("Step2: Value too large")
return value + 10
def step3(value):
if value % 2 != 0:
raise ValueError("Step3: Value must be even")
return value / 2
def pipeline(value):
v1 = step1(value)
v2 = step2(v1)
v3 = step3(v2)
return v3
print("\nPipeline processing:")
test_values = [5, 20]
for val in test_values:
try:
result = pipeline(val)
print(f" {val} → {result}")
except ValueError as e:
print(f" {val} → Failed: {e}")
if __name__ == "__main__":
main()
# Exception propagation
def main():
# Exception propagates through call stack
def level3():
print(" level3: About to raise")
raise RuntimeError("Error in level3")
def level2():
print(" level2: Calling level3")
level3()
print(" level2: This won't print")
def level1():
print("level1: Calling level2")
level2()
print("level1: This won't print")
print("Propagation demo:\n")
try:
level1()
except RuntimeError as e:
print(f"\nCaught in main: {e}")
# Function that lets exception propagate
def read_config(key):
config = {"host": "localhost", "port": 8080}
# KeyError propagates if key missing
return config[key]
def get_server_url():
host = read_config("host")
port = read_config("port")
return f"http://{host}:{port}"
print("\nConfig reading:")
try:
url = get_server_url()
print(f" URL: {url}")
except KeyError as e:
print(f" Missing config key: {e}")
try:
timeout = read_config("timeout") # Missing key
print(f" Timeout: {timeout}")
except KeyError as e:
print(f" Missing config key: {e}")
# Catch at different levels
def process_data(data):
if not data:
raise ValueError("Data is empty")
return data.upper()
def transform(data):
# Let exception propagate
return process_data(data)
def handle_request(data):
try:
# Catch here
result = transform(data)
return f"Success: {result}"
except ValueError as e:
return f"Error: {e}"
print("\nRequest handling:")
print(f" {handle_request('hello')}")
print(f" {handle_request('')}")
# Chain of operations
def step1(value):
if value < 0:
raise ValueError("Step1: Value must be positive")
return value * 2
def step2(value):
if value > 100:
raise ValueError("Step2: Value too large")
return value + 10
def step3(value):
if value % 2 != 0:
raise ValueError("Step3: Value must be even")
return value / 2
def pipeline(value):
v1 = step1(value)
v2 = step2(v1)
v3 = step3(v2)
return v3
print("\nPipeline processing:")
test_values = [-10, 60, 15]
for val in test_values:
try:
result = pipeline(val)
print(f" {val} → {result}")
except ValueError as e:
print(f" {val} → Failed: {e}")
if __name__ == "__main__":
main()
def main(): # Exception propagates through call stack
3def main():4 # Exception propagates through call stack5 def level3():6 print(" level3: About to raise")7 raise RuntimeError("Error in level3")8 9 def level2():10 print(" level2: Calling level3")11 level3()12 print(" level2: This won't print")13 14 def level1():15 print("level1: Calling level2")16 level2()17 print("level1: This won't print")18 19 print("Propagation demo:\n")outputPropagation demo:def level1():
14def level1():15 print("level1: Calling level2")16 level2()17 print("level1: This won't print")outputlevel1: Calling level2def level2():
9def level2():10 print(" level2: Calling level3")11 level3()12 print(" level2: This won't print")output level2: Calling level3def level3():
4# Exception propagates through call stack5def level3():6 print(" level3: About to raise")7 raise RuntimeError("Error in level3")output level3: About to raiseexcept RuntimeError as e:
22 level1()23except RuntimeError as e:24 print(f"\nCaught in main: {eError in level3}")2526#@help h1output Caught in main: Error in level3 Caught in main: Error in level3print(" Config reading:")
43print("\nConfig reading:")output Config reading:config ← {'host': 'localhost', 'port': 8080}
pass 1 of 332# Function that lets exception propagate33def read_config(keyhost):34 config→ {'host': 'localhost', 'port': 8080} = {"host": "localhost", "port": 8080}35 # KeyError propagates if key missing36 return config[key]localhostAll 3 passes — pass 1 is the card above pass keyconfig[key]econfig1 host localhost — {'host': 'localhost', 'port': 8080} 2 port 8080 — {'host': 'localhost', 'port': 8080} 3 timeout (empty) 'timeout' {'host': 'localhost', 'port': 8080} host ← localhost
38def get_server_url():39 host→ localhost = read_config("host")40 port = read_config("port")41 return f"http://{host}:{port}"port ← 8080
39host = read_config("host")40port→ 8080 = read_config("port")41return f"http://{hostlocalhost}:{port8080}"url ← http://localhost:8080
45try:46 url→ http://localhost:8080 = get_server_url()47 print(f" URL: {urlhttp://localhost:8080}")48except KeyError as e:output URL: http://localhost:8080except KeyError as e:
53 print(f" Timeout: {timeout}")54except KeyError as e:55 print(f" Missing config key: {e'timeout'}")5657# Catch at different levelsoutput Missing config key: 'timeout' Missing config key: 'timeout'print(" Request handling:")
75print("\nRequest handling:")76print(f" {handle_request('hello')}")77print(f" {handle_request('')}")output Request handling:def handle_request(data):
pass 1 of 267def handle_request(datahello):68 try:69 # Catch heretry: # Catch here
pass 1 of 267def handle_request(data):68 try:69 # Catch here70 result = transform(datahello)71 return f"Success: {result}"def transform(data): # Let exception propagate
pass 1 of 263def transform(datahello):64 # Let exception propagate65 return process_data(datahello)def process_data(data):
pass 1 of 257# Catch at different levels58def process_data(datahello):59 if not data:60 raise ValueError("Data is empty")61 return datahello.upper()result ← HELLO
69 # Catch here70 result→ HELLO = transform(datahello)71 return f"Success: {resultHELLO}"72except ValueError as e:print(f" {handle_request('hello')}")
75print("\nRequest handling:")76print(f" {handle_request('hello')}")77print(f" {handle_request('')}")output Success: HELLOdef handle_request(data):
pass 2 of 267def handle_request(data(empty)):68 try:69 # Catch heretry: # Catch here
pass 2 of 267def handle_request(data):68 try:69 # Catch here70 result = transform(data(empty))71 return f"Success: {result}"def transform(data): # Let exception propagate
pass 2 of 263def transform(data(empty)):64 # Let exception propagate65 return process_data(data(empty))def process_data(data):
pass 2 of 257# Catch at different levels58def process_data(data(empty)):59 if not data:60 raise ValueError("Data is empty")if not data:
58def process_data(data):59 if not data(empty):60 raise ValueError("Data is empty")61 return data.upper()except ValueError as e:
71 return f"Success: {result}"72except ValueError as e:73 return f"Error: {eData is empty}"test_values ← [10, -5, 50]
76print(f" {handle_request('hello')}")77print(f" {handle_request('')}")7879# Chain of operations80def step1(value):81 if value < 0:82 raise ValueError("Step1: Value must be positive")83 return value * 28485def step2(value):86 if value > 100:87 raise ValueError("Step2: Value too large")88 return value + 108990def step3(value):91 if value % 2 != 0:92 raise ValueError("Step3: Value must be even")93 return value / 29495def pipeline(value):96 v1 = step1(value)97 v2 = step2(v1)98 v3 = step3(v2)99 return v3100101print("\nPipeline processing:")102103test_values→ [10, -5, 50] = [10, -5, 50]104#@test_values=[5, 20], [-10, 60, 15]output Error: Data is empty Pipeline processing:for val in test_values:
pass 1 of 3106for val10 in test_values[10, -5, 50]:107 try:108 result = pipeline(val)All 3 passes — pass 1 is the card above pass valvaluee1 10 — — 2 -5 -5 Step1: Value must be positive 3 50 — — try:
pass 1 of 3106for val in test_values:107 try:108 result = pipeline(val10)109 print(f" {val} → {result}")All 3 passes — pass 1 is the card above pass valvaluee1 10 — — 2 -5 -5 Step1: Value must be positive 3 50 — — def pipeline(value):
pass 1 of 395def pipeline(value10):96 v1 = step1(value10)97 v2 = step2(v1)All 3 passes — pass 1 is the card above pass valuevale1 10 — — 2 -5 -5 Step1: Value must be positive 3 50 — — def step1(value):
pass 1 of 379# Chain of operations80def step1(value10):81 if value < 0:82 raise ValueError("Step1: Value must be positive")83 return value10 * 2All 3 passes — pass 1 is the card above pass valuevale1 10 — — 2 -5 -5 Step1: Value must be positive 3 50 — — v1 ← 20
95def pipeline(value):96 v1→ 20 = step1(value10)97 v2 = step2(v120)98 v3 = step3(v2)def step2(value):
pass 1 of 285def step2(value20):86 if value > 100:87 raise ValueError("Step2: Value too large")88 return value20 + 10v2 ← 30
96v1 = step1(value)97v2→ 30 = step2(v120)98v3 = step3(v230)99return v3def step3(value):
pass 1 of 290def step3(value30):91 if value % 2 != 0:92 raise ValueError("Step3: Value must be even")93 return value30 / 2v3 ← 15.0
97v2 = step2(v1)98v3→ 15.0 = step3(v230)99return v315.0result ← 15.0
107try:108 result→ 15.0 = pipeline(val10)109 print(f" {val10} → {result15.0}")110except ValueError as e:output 10 → 15.0if value < 0:
80def step1(value):81 if value-5 < 0:82 raise ValueError("Step1: Value must be positive")83 return value * 2except ValueError as e:
109 print(f" {val} → {result}")110except ValueError as e:111 print(f" {val-5} → Failed: {eStep1: Value must be positive}")output -5 → Failed: Step1: Value must be positive -5 → Failed: Step1: Value must be positivev1 ← 100
95def pipeline(value):96 v1→ 100 = step1(value50)97 v2 = step2(v1100)98 v3 = step3(v2)def step2(value):
pass 2 of 285def step2(value100):86 if value > 100:87 raise ValueError("Step2: Value too large")88 return value100 + 10v2 ← 110
96v1 = step1(value)97v2→ 110 = step2(v1100)98v3 = step3(v2110)99return v3def step3(value):
pass 2 of 290def step3(value110):91 if value % 2 != 0:92 raise ValueError("Step3: Value must be even")93 return value110 / 2v3 ← 55.0
97v2 = step2(v1)98v3→ 55.0 = step3(v2110)99return v355.0result ← 55.0
107try:108 result→ 55.0 = pipeline(val50)109 print(f" {val50} → {result55.0}")110except ValueError as e:output 50 → 55.0main()
113if __name__ == "__main__":114 main()
def main(): # Exception propagates through call stack
3def main():4 # Exception propagates through call stack5 def level3():6 print(" level3: About to raise")7 raise RuntimeError("Error in level3")8 9 def level2():10 print(" level2: Calling level3")11 level3()12 print(" level2: This won't print")13 14 def level1():15 print("level1: Calling level2")16 level2()17 print("level1: This won't print")18 19 print("Propagation demo:\n")outputPropagation demo:def level1():
14def level1():15 print("level1: Calling level2")16 level2()17 print("level1: This won't print")outputlevel1: Calling level2def level2():
9def level2():10 print(" level2: Calling level3")11 level3()12 print(" level2: This won't print")output level2: Calling level3def level3():
4# Exception propagates through call stack5def level3():6 print(" level3: About to raise")7 raise RuntimeError("Error in level3")output level3: About to raiseexcept RuntimeError as e:
22 level1()23except RuntimeError as e:24 print(f"\nCaught in main: {eError in level3}")25output Caught in main: Error in level3 Caught in main: Error in level3print(" Config reading:")
38print("\nConfig reading:")output Config reading:config ← {'host': 'localhost', 'port': 8080}
pass 1 of 327# Function that lets exception propagate28def read_config(keyhost):29 config→ {'host': 'localhost', 'port': 8080} = {"host": "localhost", "port": 8080}30 # KeyError propagates if key missing31 return config[key]localhostAll 3 passes — pass 1 is the card above pass keyconfig[key]econfig1 host localhost — {'host': 'localhost', 'port': 8080} 2 port 8080 — {'host': 'localhost', 'port': 8080} 3 timeout (empty) 'timeout' {'host': 'localhost', 'port': 8080} host ← localhost
33def get_server_url():34 host→ localhost = read_config("host")35 port = read_config("port")36 return f"http://{host}:{port}"port ← 8080
34host = read_config("host")35port→ 8080 = read_config("port")36return f"http://{hostlocalhost}:{port8080}"url ← http://localhost:8080
40try:41 url→ http://localhost:8080 = get_server_url()42 print(f" URL: {urlhttp://localhost:8080}")43except KeyError as e:output URL: http://localhost:8080except KeyError as e:
48 print(f" Timeout: {timeout}")49except KeyError as e:50 print(f" Missing config key: {e'timeout'}")5152# Catch at different levelsoutput Missing config key: 'timeout' Missing config key: 'timeout'print(" Request handling:")
70print("\nRequest handling:")71print(f" {handle_request('hello')}")72print(f" {handle_request('')}")output Request handling:def handle_request(data):
pass 1 of 262def handle_request(datahello):63 try:64 # Catch heretry: # Catch here
pass 1 of 262def handle_request(data):63 try:64 # Catch here65 result = transform(datahello)66 return f"Success: {result}"def transform(data): # Let exception propagate
pass 1 of 258def transform(datahello):59 # Let exception propagate60 return process_data(datahello)def process_data(data):
pass 1 of 252# Catch at different levels53def process_data(datahello):54 if not data:55 raise ValueError("Data is empty")56 return datahello.upper()result ← HELLO
64 # Catch here65 result→ HELLO = transform(datahello)66 return f"Success: {resultHELLO}"67except ValueError as e:print(f" {handle_request('hello')}")
70print("\nRequest handling:")71print(f" {handle_request('hello')}")72print(f" {handle_request('')}")output Success: HELLOdef handle_request(data):
pass 2 of 262def handle_request(data(empty)):63 try:64 # Catch heretry: # Catch here
pass 2 of 262def handle_request(data):63 try:64 # Catch here65 result = transform(data(empty))66 return f"Success: {result}"def transform(data): # Let exception propagate
pass 2 of 258def transform(data(empty)):59 # Let exception propagate60 return process_data(data(empty))def process_data(data):
pass 2 of 252# Catch at different levels53def process_data(data(empty)):54 if not data:55 raise ValueError("Data is empty")if not data:
53def process_data(data):54 if not data(empty):55 raise ValueError("Data is empty")56 return data.upper()except ValueError as e:
66 return f"Success: {result}"67except ValueError as e:68 return f"Error: {eData is empty}"test_values ← [5, 20]
71print(f" {handle_request('hello')}")72print(f" {handle_request('')}")7374# Chain of operations75def step1(value):76 if value < 0:77 raise ValueError("Step1: Value must be positive")78 return value * 27980def step2(value):81 if value > 100:82 raise ValueError("Step2: Value too large")83 return value + 108485def step3(value):86 if value % 2 != 0:87 raise ValueError("Step3: Value must be even")88 return value / 28990def pipeline(value):91 v1 = step1(value)92 v2 = step2(v1)93 v3 = step3(v2)94 return v39596print("\nPipeline processing:")9798test_values→ [5, 20] = [5, 20]output Error: Data is empty Pipeline processing:for val in test_values:
pass 1 of 2100for val5 in test_values[5, 20]:101 try:102 result = pipeline(val)try:
pass 1 of 2100for val in test_values:101 try:102 result = pipeline(val5)103 print(f" {val} → {result}")def pipeline(value):
pass 1 of 290def pipeline(value5):91 v1 = step1(value5)92 v2 = step2(v1)def step1(value):
pass 1 of 274# Chain of operations75def step1(value5):76 if value < 0:77 raise ValueError("Step1: Value must be positive")78 return value5 * 2v1 ← 10
90def pipeline(value):91 v1→ 10 = step1(value5)92 v2 = step2(v110)93 v3 = step3(v2)def step2(value):
pass 1 of 280def step2(value10):81 if value > 100:82 raise ValueError("Step2: Value too large")83 return value10 + 10v2 ← 20
91v1 = step1(value)92v2→ 20 = step2(v110)93v3 = step3(v220)94return v3def step3(value):
pass 1 of 285def step3(value20):86 if value % 2 != 0:87 raise ValueError("Step3: Value must be even")88 return value20 / 2v3 ← 10.0
92v2 = step2(v1)93v3→ 10.0 = step3(v220)94return v310.0result ← 10.0
101try:102 result→ 10.0 = pipeline(val5)103 print(f" {val5} → {result10.0}")104except ValueError as e:output 5 → 10.0for val in test_values:
pass 2 of 2100for val20 in test_values[5, 20]:101 try:102 result = pipeline(val)try:
pass 2 of 2100for val in test_values:101 try:102 result = pipeline(val20)103 print(f" {val} → {result}")def pipeline(value):
pass 2 of 290def pipeline(value20):91 v1 = step1(value20)92 v2 = step2(v1)def step1(value):
pass 2 of 274# Chain of operations75def step1(value20):76 if value < 0:77 raise ValueError("Step1: Value must be positive")78 return value20 * 2v1 ← 40
90def pipeline(value):91 v1→ 40 = step1(value20)92 v2 = step2(v140)93 v3 = step3(v2)def step2(value):
pass 2 of 280def step2(value40):81 if value > 100:82 raise ValueError("Step2: Value too large")83 return value40 + 10v2 ← 50
91v1 = step1(value)92v2→ 50 = step2(v140)93v3 = step3(v250)94return v3def step3(value):
pass 2 of 285def step3(value50):86 if value % 2 != 0:87 raise ValueError("Step3: Value must be even")88 return value50 / 2v3 ← 25.0
92v2 = step2(v1)93v3→ 25.0 = step3(v250)94return v325.0result ← 25.0
101try:102 result→ 25.0 = pipeline(val20)103 print(f" {val20} → {result25.0}")104except ValueError as e:output 20 → 25.0main()
107if __name__ == "__main__":108 main()
def main(): # Exception propagates through call stack
3def main():4 # Exception propagates through call stack5 def level3():6 print(" level3: About to raise")7 raise RuntimeError("Error in level3")8 9 def level2():10 print(" level2: Calling level3")11 level3()12 print(" level2: This won't print")13 14 def level1():15 print("level1: Calling level2")16 level2()17 print("level1: This won't print")18 19 print("Propagation demo:\n")outputPropagation demo:def level1():
14def level1():15 print("level1: Calling level2")16 level2()17 print("level1: This won't print")outputlevel1: Calling level2def level2():
9def level2():10 print(" level2: Calling level3")11 level3()12 print(" level2: This won't print")output level2: Calling level3def level3():
4# Exception propagates through call stack5def level3():6 print(" level3: About to raise")7 raise RuntimeError("Error in level3")output level3: About to raiseexcept RuntimeError as e:
22 level1()23except RuntimeError as e:24 print(f"\nCaught in main: {eError in level3}")25output Caught in main: Error in level3 Caught in main: Error in level3print(" Config reading:")
38print("\nConfig reading:")output Config reading:config ← {'host': 'localhost', 'port': 8080}
pass 1 of 327# Function that lets exception propagate28def read_config(keyhost):29 config→ {'host': 'localhost', 'port': 8080} = {"host": "localhost", "port": 8080}30 # KeyError propagates if key missing31 return config[key]localhostAll 3 passes — pass 1 is the card above pass keyconfig[key]econfig1 host localhost — {'host': 'localhost', 'port': 8080} 2 port 8080 — {'host': 'localhost', 'port': 8080} 3 timeout (empty) 'timeout' {'host': 'localhost', 'port': 8080} host ← localhost
33def get_server_url():34 host→ localhost = read_config("host")35 port = read_config("port")36 return f"http://{host}:{port}"port ← 8080
34host = read_config("host")35port→ 8080 = read_config("port")36return f"http://{hostlocalhost}:{port8080}"url ← http://localhost:8080
40try:41 url→ http://localhost:8080 = get_server_url()42 print(f" URL: {urlhttp://localhost:8080}")43except KeyError as e:output URL: http://localhost:8080except KeyError as e:
48 print(f" Timeout: {timeout}")49except KeyError as e:50 print(f" Missing config key: {e'timeout'}")5152# Catch at different levelsoutput Missing config key: 'timeout' Missing config key: 'timeout'print(" Request handling:")
70print("\nRequest handling:")71print(f" {handle_request('hello')}")72print(f" {handle_request('')}")output Request handling:def handle_request(data):
pass 1 of 262def handle_request(datahello):63 try:64 # Catch heretry: # Catch here
pass 1 of 262def handle_request(data):63 try:64 # Catch here65 result = transform(datahello)66 return f"Success: {result}"def transform(data): # Let exception propagate
pass 1 of 258def transform(datahello):59 # Let exception propagate60 return process_data(datahello)def process_data(data):
pass 1 of 252# Catch at different levels53def process_data(datahello):54 if not data:55 raise ValueError("Data is empty")56 return datahello.upper()result ← HELLO
64 # Catch here65 result→ HELLO = transform(datahello)66 return f"Success: {resultHELLO}"67except ValueError as e:print(f" {handle_request('hello')}")
70print("\nRequest handling:")71print(f" {handle_request('hello')}")72print(f" {handle_request('')}")output Success: HELLOdef handle_request(data):
pass 2 of 262def handle_request(data(empty)):63 try:64 # Catch heretry: # Catch here
pass 2 of 262def handle_request(data):63 try:64 # Catch here65 result = transform(data(empty))66 return f"Success: {result}"def transform(data): # Let exception propagate
pass 2 of 258def transform(data(empty)):59 # Let exception propagate60 return process_data(data(empty))def process_data(data):
pass 2 of 252# Catch at different levels53def process_data(data(empty)):54 if not data:55 raise ValueError("Data is empty")if not data:
53def process_data(data):54 if not data(empty):55 raise ValueError("Data is empty")56 return data.upper()except ValueError as e:
66 return f"Success: {result}"67except ValueError as e:68 return f"Error: {eData is empty}"test_values ← [-10, 60, 15]
71print(f" {handle_request('hello')}")72print(f" {handle_request('')}")7374# Chain of operations75def step1(value):76 if value < 0:77 raise ValueError("Step1: Value must be positive")78 return value * 27980def step2(value):81 if value > 100:82 raise ValueError("Step2: Value too large")83 return value + 108485def step3(value):86 if value % 2 != 0:87 raise ValueError("Step3: Value must be even")88 return value / 28990def pipeline(value):91 v1 = step1(value)92 v2 = step2(v1)93 v3 = step3(v2)94 return v39596print("\nPipeline processing:")9798test_values→ [-10, 60, 15] = [-10, 60, 15]output Error: Data is empty Pipeline processing:for val in test_values:
pass 1 of 3100for val-10 in test_values[-10, 60, 15]:101 try:102 result = pipeline(val)All 3 passes — pass 1 is the card above pass valvaluee1 -10 -10 Step1: Value must be positive 2 60 — — 3 15 — — try:
pass 1 of 3100for val in test_values:101 try:102 result = pipeline(val-10)103 print(f" {val} → {result}")All 3 passes — pass 1 is the card above pass valvaluee1 -10 -10 Step1: Value must be positive 2 60 — — 3 15 — — def pipeline(value):
pass 1 of 390def pipeline(value-10):91 v1 = step1(value-10)92 v2 = step2(v1)All 3 passes — pass 1 is the card above pass valuevale1 -10 -10 Step1: Value must be positive 2 60 — — 3 15 — — def step1(value):
pass 1 of 374# Chain of operations75def step1(value-10):76 if value < 0:77 raise ValueError("Step1: Value must be positive")All 3 passes — pass 1 is the card above pass valuevale1 -10 -10 Step1: Value must be positive 2 60 — — 3 15 — — if value < 0:
75def step1(value):76 if value-10 < 0:77 raise ValueError("Step1: Value must be positive")78 return value * 2except ValueError as e:
pass 1 of 2103 print(f" {val} → {result}")104except ValueError as e:105 print(f" {val-10} → Failed: {eStep1: Value must be positive}")output -10 → Failed: Step1: Value must be positive -10 → Failed: Step1: Value must be positivev1 ← 120
90def pipeline(value):91 v1→ 120 = step1(value60)92 v2 = step2(v1120)93 v3 = step3(v2)def step2(value):
pass 1 of 280def step2(value120):81 if value > 100:82 raise ValueError("Step2: Value too large")if value > 100:
80def step2(value):81 if value120 > 100:82 raise ValueError("Step2: Value too large")83 return value + 10except ValueError as e:
pass 2 of 2103 print(f" {val} → {result}")104except ValueError as e:105 print(f" {val60} → Failed: {eStep2: Value too large}")output 60 → Failed: Step2: Value too large 60 → Failed: Step2: Value too largev1 ← 30
90def pipeline(value):91 v1→ 30 = step1(value15)92 v2 = step2(v130)93 v3 = step3(v2)def step2(value):
pass 2 of 280def step2(value30):81 if value > 100:82 raise ValueError("Step2: Value too large")83 return value30 + 10v2 ← 40
91v1 = step1(value)92v2→ 40 = step2(v130)93v3 = step3(v240)94return v3def step3(value):
85def step3(value40):86 if value % 2 != 0:87 raise ValueError("Step3: Value must be even")88 return value40 / 2v3 ← 20.0
92v2 = step2(v1)93v3→ 20.0 = step3(v240)94return v320.0result ← 20.0
101try:102 result→ 20.0 = pipeline(val15)103 print(f" {val15} → {result20.0}")104except ValueError as e:output 15 → 20.0main()
107if __name__ == "__main__":108 main()
Uncaught exception travels up the call stack to the first handler.
Include error details
Provide useful information in the exception message.
# Raising exceptions with messages
def main():
# Detailed error messages
def withdraw(balance, amount):
if amount <= 0:
raise ValueError(f"Withdrawal amount must be positive, got {amount}")
if amount > balance:
raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")
return balance - amount
print("Bank withdrawals:\n")
balance = 100
# Successful withdrawal
try:
new_balance = withdraw(balance, 30)
print(f" Withdrew $30: New balance ${new_balance}")
balance = new_balance
except ValueError as e:
print(f" Error: {e}")
# Invalid amount
try:
new_balance = withdraw(balance, -10)
print(f" Withdrew $-10: New balance ${new_balance}")
except ValueError as e:
print(f" Error: {e}")
# Insufficient funds
try:
new_balance = withdraw(balance, 200)
print(f" Withdrew $200: New balance ${new_balance}")
except ValueError as e:
print(f" Error: {e}")
# Type-specific error messages
def calculate_discount(price, discount_percent):
if not isinstance(price, (int, float)):
raise TypeError(f"Price must be numeric, got {type(price).__name__}")
if not isinstance(discount_percent, (int, float)):
raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")
if discount_percent < 0 or discount_percent > 100:
raise ValueError(f"Discount must be 0-100%, got {discount_percent}")
return price * (1 - discount_percent / 100)
print("\nDiscount calculations:")
test_cases = [
(100, 10),
(100, "10"),
("100", 10),
(100, 150)
]
for price, discount in test_cases:
try:
final_price = calculate_discount(price, discount)
print(f" ${price} - {discount}% = ${final_price:.2f}")
except (TypeError, ValueError) as e:
print(f" ${price} - {discount}%: {e}")
# Index validation with context
def get_item(items, index):
if not isinstance(index, int):
raise TypeError(f"Index must be integer, got {type(index).__name__}")
if index < 0:
raise IndexError(f"Index must be non-negative, got {index}")
if index >= len(items):
raise IndexError(f"Index {index} out of range (list size: {len(items)})")
return items[index]
print("\nList access:")
fruits = ["apple", "banana", "cherry"]
indices = [0, 5, -1, "2"]
for idx in indices:
try:
fruit = get_item(fruits, idx)
print(f" fruits[{idx}] = {fruit}")
except (TypeError, IndexError) as e:
print(f" fruits[{idx}]: {e}")
if __name__ == "__main__":
main()
# Raising exceptions with messages
def main():
# Detailed error messages
def withdraw(balance, amount):
if amount <= 0:
raise ValueError(f"Withdrawal amount must be positive, got {amount}")
if amount > balance:
raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")
return balance - amount
print("Bank withdrawals:\n")
balance = 50
# Successful withdrawal
try:
new_balance = withdraw(balance, 30)
print(f" Withdrew $30: New balance ${new_balance}")
balance = new_balance
except ValueError as e:
print(f" Error: {e}")
# Invalid amount
try:
new_balance = withdraw(balance, -10)
print(f" Withdrew $-10: New balance ${new_balance}")
except ValueError as e:
print(f" Error: {e}")
# Insufficient funds
try:
new_balance = withdraw(balance, 200)
print(f" Withdrew $200: New balance ${new_balance}")
except ValueError as e:
print(f" Error: {e}")
# Type-specific error messages
def calculate_discount(price, discount_percent):
if not isinstance(price, (int, float)):
raise TypeError(f"Price must be numeric, got {type(price).__name__}")
if not isinstance(discount_percent, (int, float)):
raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")
if discount_percent < 0 or discount_percent > 100:
raise ValueError(f"Discount must be 0-100%, got {discount_percent}")
return price * (1 - discount_percent / 100)
print("\nDiscount calculations:")
test_cases = [
(100, 10),
(100, "10"),
("100", 10),
(100, 150)
]
for price, discount in test_cases:
try:
final_price = calculate_discount(price, discount)
print(f" ${price} - {discount}% = ${final_price:.2f}")
except (TypeError, ValueError) as e:
print(f" ${price} - {discount}%: {e}")
# Index validation with context
def get_item(items, index):
if not isinstance(index, int):
raise TypeError(f"Index must be integer, got {type(index).__name__}")
if index < 0:
raise IndexError(f"Index must be non-negative, got {index}")
if index >= len(items):
raise IndexError(f"Index {index} out of range (list size: {len(items)})")
return items[index]
print("\nList access:")
fruits = ["apple", "banana", "cherry"]
indices = [0, 5, -1, "2"]
for idx in indices:
try:
fruit = get_item(fruits, idx)
print(f" fruits[{idx}] = {fruit}")
except (TypeError, IndexError) as e:
print(f" fruits[{idx}]: {e}")
if __name__ == "__main__":
main()
# Raising exceptions with messages
def main():
# Detailed error messages
def withdraw(balance, amount):
if amount <= 0:
raise ValueError(f"Withdrawal amount must be positive, got {amount}")
if amount > balance:
raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")
return balance - amount
print("Bank withdrawals:\n")
balance = 200
# Successful withdrawal
try:
new_balance = withdraw(balance, 30)
print(f" Withdrew $30: New balance ${new_balance}")
balance = new_balance
except ValueError as e:
print(f" Error: {e}")
# Invalid amount
try:
new_balance = withdraw(balance, -10)
print(f" Withdrew $-10: New balance ${new_balance}")
except ValueError as e:
print(f" Error: {e}")
# Insufficient funds
try:
new_balance = withdraw(balance, 200)
print(f" Withdrew $200: New balance ${new_balance}")
except ValueError as e:
print(f" Error: {e}")
# Type-specific error messages
def calculate_discount(price, discount_percent):
if not isinstance(price, (int, float)):
raise TypeError(f"Price must be numeric, got {type(price).__name__}")
if not isinstance(discount_percent, (int, float)):
raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")
if discount_percent < 0 or discount_percent > 100:
raise ValueError(f"Discount must be 0-100%, got {discount_percent}")
return price * (1 - discount_percent / 100)
print("\nDiscount calculations:")
test_cases = [
(100, 10),
(100, "10"),
("100", 10),
(100, 150)
]
for price, discount in test_cases:
try:
final_price = calculate_discount(price, discount)
print(f" ${price} - {discount}% = ${final_price:.2f}")
except (TypeError, ValueError) as e:
print(f" ${price} - {discount}%: {e}")
# Index validation with context
def get_item(items, index):
if not isinstance(index, int):
raise TypeError(f"Index must be integer, got {type(index).__name__}")
if index < 0:
raise IndexError(f"Index must be non-negative, got {index}")
if index >= len(items):
raise IndexError(f"Index {index} out of range (list size: {len(items)})")
return items[index]
print("\nList access:")
fruits = ["apple", "banana", "cherry"]
indices = [0, 5, -1, "2"]
for idx in indices:
try:
fruit = get_item(fruits, idx)
print(f" fruits[{idx}] = {fruit}")
except (TypeError, IndexError) as e:
print(f" fruits[{idx}]: {e}")
if __name__ == "__main__":
main()
balance ← 100
3def main():4 # Detailed error messages5 def withdraw(balance, amount):6 if amount <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8 if amount > balance:9 raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")10 return balance - amount11 12 print("Bank withdrawals:\n")13 14 balance→ 100 = 10015 #@balance=50, 200outputBank withdrawals:try:
17# Successful withdrawal18try:19 new_balance = withdraw(balance100, 30)20 print(f" Withdrew $30: New balance ${new_balance}")def withdraw(balance, amount):
pass 1 of 34# Detailed error messages5def withdraw(balance100, amount30):6 if amount <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8 if amount > balance:9 raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")10 return balance100 - amount30All 3 passes — pass 1 is the card above pass balanceamounte1 100 30 — 2 70 -10 Withdrawal amount must be positive, got -10 3 70 200 Insufficient funds: balance=70, requested=200 new_balance ← 70, balance ← 70
18try:19 new_balance→ 70 = withdraw(balance100, 30)20 print(f" Withdrew $30: New balance ${new_balance70}")21 balance→ 70 = new_balance7022except ValueError as e:output Withdrew $30: New balance $70try:
25# Invalid amount26try:27 new_balance = withdraw(balance70, -10)28 print(f" Withdrew $-10: New balance ${new_balance}")if amount <= 0:
5def withdraw(balance, amount):6 if amount-10 <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount-10}")8 if amount > balance:except ValueError as e:
28 print(f" Withdrew $-10: New balance ${new_balance}")29except ValueError as e:30 print(f" Error: {eWithdrawal amount must be positive, got -10}")3132# Insufficient fundsoutput Error: Withdrawal amount must be positive, got -10 Error: Withdrawal amount must be positive, got -10try:
32# Insufficient funds33try:34 new_balance = withdraw(balance70, 200)35 print(f" Withdrew $200: New balance ${new_balance}")if amount > balance:
7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8if amount200 > balance70:9 raise ValueError(f"Insufficient funds: balance={balance70}, requested={amount200}")10return balance - amountexcept ValueError as e:
35 print(f" Withdrew $200: New balance ${new_balance}")36except ValueError as e:37 print(f" Error: {eInsufficient funds: balance=70, requested=200}")3839#@help h1output Error: Insufficient funds: balance=70, requested=200 Error: Insufficient funds: balance=70, requested=200test_cases ← [(100, 10), (100, '10'), ('100', 10), (100, 150)]
56print("\nDiscount calculations:")5758test_cases→ [(100, 10), (100, '10'), ('100', 10), (100, 150)] = [59 (100, 10),60 (100, "10"),61 ("100", 10),62 (100, 150)63]64#@test_cases=[(50, 20), (50, 110)]output Discount calculations:for price, discount in test_cases:
pass 1 of 466for price100, discount10 in test_cases[(100, 10), (100, '10'), ('100', 10), (100, 150)]:67 try:68 final_price = calculate_discount(price, discount)All 4 passes — pass 1 is the card above pass discountdiscount_percent1 10 — 2 10 10 3 10 — 4 150 150 try:
pass 1 of 466for price, discount in test_cases:67 try:68 final_price = calculate_discount(price100, discount10)69 print(f" ${price} - {discount}% = ${final_price:.2f}")All 4 passes — pass 1 is the card above pass discountdiscount_percent1 10 — 2 10 10 3 10 — 4 150 150 def calculate_discount(price, discount_percent):
pass 1 of 445# Type-specific error messages46def calculate_discount(price100, discount_percent10):47 if not isinstance(price, (int, float)):48 raise TypeError(f"Price must be numeric, got {type(price).__name__}")49 if not isinstance(discount_percent, (int, float)):50 raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")51 if discount_percent < 0 or discount_percent > 100:52 raise ValueError(f"Discount must be 0-100%, got {discount_percent}")53 54 return price100 * (1 - discount_percent10 / 100)All 4 passes — pass 1 is the card above pass discount_percent1 10 2 10 3 10 4 150 final_price ← 90.0
67try:68 final_price→ 90.0 = calculate_discount(price100, discount10)69 print(f" ${price100} - {discount10}% = ${final_price90.0:.2f}")70except (TypeError, ValueError) as e:output $100 - 10% = $90.00if not isinstance(discount_percent, (int, float)):
48 raise TypeError(f"Price must be numeric, got {type(price).__name__}")49if not isinstance(discount_percent10, (int, float)):50 raise TypeError(f"Discount must be numeric, got {type(discount_percent10).__name__}")51if discount_percent < 0 or discount_percent > 100:except (TypeError, ValueError) as e:
pass 1 of 369 print(f" ${price} - {discount}% = ${final_price:.2f}")70except (TypeError, ValueError) as e:71 print(f" ${price100} - {discount10}%: {eDiscount must be numeric, got str}")output $100 - 10%: Discount must be numeric, got str $100 - 10%: Discount must be numeric, got strAll 3 passes — pass 1 is the card above pass discountediscount_percent1 10 Discount must be numeric, got str — 2 10 Price must be numeric, got str 150 3 150 Discount must be 0-100%, got 150 — if not isinstance(price, (int, float)):
46def calculate_discount(price, discount_percent):47 if not isinstance(price100, (int, float)):48 raise TypeError(f"Price must be numeric, got {type(price100).__name__}")49 if not isinstance(discount_percent, (int, float)):if discount_percent < 0 or discount_percent > 100:
50 raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")51if discount_percent150 < 0 or discount_percent > 100:52 raise ValueError(f"Discount must be 0-100%, got {discount_percent150}")fruits ← ['apple', 'banana', 'cherry'], indices ← [0, 5, -1, '2']
83print("\nList access:")8485fruits→ ['apple', 'banana', 'cherry'] = ["apple", "banana", "cherry"]86indices→ [0, 5, -1, '2'] = [0, 5, -1, "2"]output List access:for idx in indices:
pass 1 of 488for idx0 in indices[0, 5, -1, '2']:89 try:90 fruit = get_item(fruits, idx)All 4 passes — pass 1 is the card above pass idxindexitems1 0 — — 2 5 5 ['apple', 'banana', 'cherry'] 3 -1 -1 — 4 2 2 — try:
pass 1 of 488for idx in indices:89 try:90 fruit = get_item(fruits['apple', 'banana', 'cherry'], idx0)91 print(f" fruits[{idx}] = {fruit}")All 4 passes — pass 1 is the card above pass idxindexitems1 0 — — 2 5 5 ['apple', 'banana', 'cherry'] 3 -1 -1 — 4 2 2 — def get_item(items, index):
pass 1 of 473# Index validation with context74def get_item(items['apple', 'banana', 'cherry'], index0):75 if not isinstance(index, int):76 raise TypeError(f"Index must be integer, got {type(index).__name__}")77 if index < 0:78 raise IndexError(f"Index must be non-negative, got {index}")79 if index >= len(items):80 raise IndexError(f"Index {index} out of range (list size: {len(items)})")81 return items[index]appleAll 4 passes — pass 1 is the card above pass indexitems[index]1 0 apple 2 5 — 3 -1 — 4 2 — fruit ← apple
89try:90 fruit→ apple = get_item(fruits['apple', 'banana', 'cherry'], idx0)91 print(f" fruits[{idx0}] = {fruitapple}")92except (TypeError, IndexError) as e:output fruits[0] = appleif index >= len(items):
78 raise IndexError(f"Index must be non-negative, got {index}")79if index5 >= len(items['apple', 'banana', 'cherry']):80 raise IndexError(f"Index {index5} out of range (list size: {len(items['apple', 'banana', 'cherry'])})")81return items[index]except (TypeError, IndexError) as e:
pass 1 of 391 print(f" fruits[{idx}] = {fruit}")92except (TypeError, IndexError) as e:93 print(f" fruits[{idx5}]: {eIndex 5 out of range (list size: 3)}")output fruits[5]: Index 5 out of range (list size: 3) fruits[5]: Index 5 out of range (list size: 3)All 3 passes — pass 1 is the card above pass idxeindex1 5 Index 5 out of range (list size: 3) -1 2 -1 Index must be non-negative, got -1 2 3 2 Index must be integer, got str — if index < 0:
76 raise TypeError(f"Index must be integer, got {type(index).__name__}")77if index-1 < 0:78 raise IndexError(f"Index must be non-negative, got {index-1}")79if index >= len(items):if not isinstance(index, int):
74def get_item(items, index):75 if not isinstance(index2, int):76 raise TypeError(f"Index must be integer, got {type(index2).__name__}")77 if index < 0:main()
95if __name__ == "__main__":96 main()
balance ← 50
3def main():4 # Detailed error messages5 def withdraw(balance, amount):6 if amount <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8 if amount > balance:9 raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")10 return balance - amount11 12 print("Bank withdrawals:\n")13 14 balance→ 50 = 50outputBank withdrawals:try:
16# Successful withdrawal17try:18 new_balance = withdraw(balance50, 30)19 print(f" Withdrew $30: New balance ${new_balance}")def withdraw(balance, amount):
pass 1 of 34# Detailed error messages5def withdraw(balance50, amount30):6 if amount <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8 if amount > balance:9 raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")10 return balance50 - amount30All 3 passes — pass 1 is the card above pass balanceamounte1 50 30 — 2 20 -10 Withdrawal amount must be positive, got -10 3 20 200 Insufficient funds: balance=20, requested=200 new_balance ← 20, balance ← 20
17try:18 new_balance→ 20 = withdraw(balance50, 30)19 print(f" Withdrew $30: New balance ${new_balance20}")20 balance→ 20 = new_balance2021except ValueError as e:output Withdrew $30: New balance $20try:
24# Invalid amount25try:26 new_balance = withdraw(balance20, -10)27 print(f" Withdrew $-10: New balance ${new_balance}")if amount <= 0:
5def withdraw(balance, amount):6 if amount-10 <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount-10}")8 if amount > balance:except ValueError as e:
27 print(f" Withdrew $-10: New balance ${new_balance}")28except ValueError as e:29 print(f" Error: {eWithdrawal amount must be positive, got -10}")3031# Insufficient fundsoutput Error: Withdrawal amount must be positive, got -10 Error: Withdrawal amount must be positive, got -10try:
31# Insufficient funds32try:33 new_balance = withdraw(balance20, 200)34 print(f" Withdrew $200: New balance ${new_balance}")if amount > balance:
7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8if amount200 > balance20:9 raise ValueError(f"Insufficient funds: balance={balance20}, requested={amount200}")10return balance - amountexcept ValueError as e:
34 print(f" Withdrew $200: New balance ${new_balance}")35except ValueError as e:36 print(f" Error: {eInsufficient funds: balance=20, requested=200}")37output Error: Insufficient funds: balance=20, requested=200 Error: Insufficient funds: balance=20, requested=200test_cases ← [(100, 10), (100, '10'), ('100', 10), (100, 150)]
50print("\nDiscount calculations:")5152test_cases→ [(100, 10), (100, '10'), ('100', 10), (100, 150)] = [53 (100, 10),54 (100, "10"),55 ("100", 10),56 (100, 150)57]output Discount calculations:for price, discount in test_cases:
pass 1 of 459for price100, discount10 in test_cases[(100, 10), (100, '10'), ('100', 10), (100, 150)]:60 try:61 final_price = calculate_discount(price, discount)All 4 passes — pass 1 is the card above pass discountdiscount_percent1 10 — 2 10 10 3 10 — 4 150 150 try:
pass 1 of 459for price, discount in test_cases:60 try:61 final_price = calculate_discount(price100, discount10)62 print(f" ${price} - {discount}% = ${final_price:.2f}")All 4 passes — pass 1 is the card above pass discountdiscount_percent1 10 — 2 10 10 3 10 — 4 150 150 def calculate_discount(price, discount_percent):
pass 1 of 439# Type-specific error messages40def calculate_discount(price100, discount_percent10):41 if not isinstance(price, (int, float)):42 raise TypeError(f"Price must be numeric, got {type(price).__name__}")43 if not isinstance(discount_percent, (int, float)):44 raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")45 if discount_percent < 0 or discount_percent > 100:46 raise ValueError(f"Discount must be 0-100%, got {discount_percent}")47 48 return price100 * (1 - discount_percent10 / 100)All 4 passes — pass 1 is the card above pass discount_percent1 10 2 10 3 10 4 150 final_price ← 90.0
60try:61 final_price→ 90.0 = calculate_discount(price100, discount10)62 print(f" ${price100} - {discount10}% = ${final_price90.0:.2f}")63except (TypeError, ValueError) as e:output $100 - 10% = $90.00if not isinstance(discount_percent, (int, float)):
42 raise TypeError(f"Price must be numeric, got {type(price).__name__}")43if not isinstance(discount_percent10, (int, float)):44 raise TypeError(f"Discount must be numeric, got {type(discount_percent10).__name__}")45if discount_percent < 0 or discount_percent > 100:except (TypeError, ValueError) as e:
pass 1 of 362 print(f" ${price} - {discount}% = ${final_price:.2f}")63except (TypeError, ValueError) as e:64 print(f" ${price100} - {discount10}%: {eDiscount must be numeric, got str}")output $100 - 10%: Discount must be numeric, got str $100 - 10%: Discount must be numeric, got strAll 3 passes — pass 1 is the card above pass discountediscount_percent1 10 Discount must be numeric, got str — 2 10 Price must be numeric, got str 150 3 150 Discount must be 0-100%, got 150 — if not isinstance(price, (int, float)):
40def calculate_discount(price, discount_percent):41 if not isinstance(price100, (int, float)):42 raise TypeError(f"Price must be numeric, got {type(price100).__name__}")43 if not isinstance(discount_percent, (int, float)):if discount_percent < 0 or discount_percent > 100:
44 raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")45if discount_percent150 < 0 or discount_percent > 100:46 raise ValueError(f"Discount must be 0-100%, got {discount_percent150}")fruits ← ['apple', 'banana', 'cherry'], indices ← [0, 5, -1, '2']
76print("\nList access:")7778fruits→ ['apple', 'banana', 'cherry'] = ["apple", "banana", "cherry"]79indices→ [0, 5, -1, '2'] = [0, 5, -1, "2"]output List access:for idx in indices:
pass 1 of 481for idx0 in indices[0, 5, -1, '2']:82 try:83 fruit = get_item(fruits, idx)All 4 passes — pass 1 is the card above pass idxindexitems1 0 — — 2 5 5 ['apple', 'banana', 'cherry'] 3 -1 -1 — 4 2 2 — try:
pass 1 of 481for idx in indices:82 try:83 fruit = get_item(fruits['apple', 'banana', 'cherry'], idx0)84 print(f" fruits[{idx}] = {fruit}")All 4 passes — pass 1 is the card above pass idxindexitems1 0 — — 2 5 5 ['apple', 'banana', 'cherry'] 3 -1 -1 — 4 2 2 — def get_item(items, index):
pass 1 of 466# Index validation with context67def get_item(items['apple', 'banana', 'cherry'], index0):68 if not isinstance(index, int):69 raise TypeError(f"Index must be integer, got {type(index).__name__}")70 if index < 0:71 raise IndexError(f"Index must be non-negative, got {index}")72 if index >= len(items):73 raise IndexError(f"Index {index} out of range (list size: {len(items)})")74 return items[index]appleAll 4 passes — pass 1 is the card above pass indexitems[index]1 0 apple 2 5 — 3 -1 — 4 2 — fruit ← apple
82try:83 fruit→ apple = get_item(fruits['apple', 'banana', 'cherry'], idx0)84 print(f" fruits[{idx0}] = {fruitapple}")85except (TypeError, IndexError) as e:output fruits[0] = appleif index >= len(items):
71 raise IndexError(f"Index must be non-negative, got {index}")72if index5 >= len(items['apple', 'banana', 'cherry']):73 raise IndexError(f"Index {index5} out of range (list size: {len(items['apple', 'banana', 'cherry'])})")74return items[index]except (TypeError, IndexError) as e:
pass 1 of 384 print(f" fruits[{idx}] = {fruit}")85except (TypeError, IndexError) as e:86 print(f" fruits[{idx5}]: {eIndex 5 out of range (list size: 3)}")output fruits[5]: Index 5 out of range (list size: 3) fruits[5]: Index 5 out of range (list size: 3)All 3 passes — pass 1 is the card above pass idxeindex1 5 Index 5 out of range (list size: 3) -1 2 -1 Index must be non-negative, got -1 2 3 2 Index must be integer, got str — if index < 0:
69 raise TypeError(f"Index must be integer, got {type(index).__name__}")70if index-1 < 0:71 raise IndexError(f"Index must be non-negative, got {index-1}")72if index >= len(items):if not isinstance(index, int):
67def get_item(items, index):68 if not isinstance(index2, int):69 raise TypeError(f"Index must be integer, got {type(index2).__name__}")70 if index < 0:main()
88if __name__ == "__main__":89 main()
balance ← 200
3def main():4 # Detailed error messages5 def withdraw(balance, amount):6 if amount <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8 if amount > balance:9 raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")10 return balance - amount11 12 print("Bank withdrawals:\n")13 14 balance→ 200 = 200outputBank withdrawals:try:
16# Successful withdrawal17try:18 new_balance = withdraw(balance200, 30)19 print(f" Withdrew $30: New balance ${new_balance}")def withdraw(balance, amount):
pass 1 of 34# Detailed error messages5def withdraw(balance200, amount30):6 if amount <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8 if amount > balance:9 raise ValueError(f"Insufficient funds: balance={balance}, requested={amount}")10 return balance200 - amount30All 3 passes — pass 1 is the card above pass balanceamounte1 200 30 — 2 170 -10 Withdrawal amount must be positive, got -10 3 170 200 Insufficient funds: balance=170, requested=200 new_balance ← 170, balance ← 170
17try:18 new_balance→ 170 = withdraw(balance200, 30)19 print(f" Withdrew $30: New balance ${new_balance170}")20 balance→ 170 = new_balance17021except ValueError as e:output Withdrew $30: New balance $170try:
24# Invalid amount25try:26 new_balance = withdraw(balance170, -10)27 print(f" Withdrew $-10: New balance ${new_balance}")if amount <= 0:
5def withdraw(balance, amount):6 if amount-10 <= 0:7 raise ValueError(f"Withdrawal amount must be positive, got {amount-10}")8 if amount > balance:except ValueError as e:
27 print(f" Withdrew $-10: New balance ${new_balance}")28except ValueError as e:29 print(f" Error: {eWithdrawal amount must be positive, got -10}")3031# Insufficient fundsoutput Error: Withdrawal amount must be positive, got -10 Error: Withdrawal amount must be positive, got -10try:
31# Insufficient funds32try:33 new_balance = withdraw(balance170, 200)34 print(f" Withdrew $200: New balance ${new_balance}")if amount > balance:
7 raise ValueError(f"Withdrawal amount must be positive, got {amount}")8if amount200 > balance170:9 raise ValueError(f"Insufficient funds: balance={balance170}, requested={amount200}")10return balance - amountexcept ValueError as e:
34 print(f" Withdrew $200: New balance ${new_balance}")35except ValueError as e:36 print(f" Error: {eInsufficient funds: balance=170, requested=200}")37output Error: Insufficient funds: balance=170, requested=200 Error: Insufficient funds: balance=170, requested=200test_cases ← [(100, 10), (100, '10'), ('100', 10), (100, 150)]
50print("\nDiscount calculations:")5152test_cases→ [(100, 10), (100, '10'), ('100', 10), (100, 150)] = [53 (100, 10),54 (100, "10"),55 ("100", 10),56 (100, 150)57]output Discount calculations:for price, discount in test_cases:
pass 1 of 459for price100, discount10 in test_cases[(100, 10), (100, '10'), ('100', 10), (100, 150)]:60 try:61 final_price = calculate_discount(price, discount)All 4 passes — pass 1 is the card above pass discountdiscount_percent1 10 — 2 10 10 3 10 — 4 150 150 try:
pass 1 of 459for price, discount in test_cases:60 try:61 final_price = calculate_discount(price100, discount10)62 print(f" ${price} - {discount}% = ${final_price:.2f}")All 4 passes — pass 1 is the card above pass discountdiscount_percent1 10 — 2 10 10 3 10 — 4 150 150 def calculate_discount(price, discount_percent):
pass 1 of 439# Type-specific error messages40def calculate_discount(price100, discount_percent10):41 if not isinstance(price, (int, float)):42 raise TypeError(f"Price must be numeric, got {type(price).__name__}")43 if not isinstance(discount_percent, (int, float)):44 raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")45 if discount_percent < 0 or discount_percent > 100:46 raise ValueError(f"Discount must be 0-100%, got {discount_percent}")47 48 return price100 * (1 - discount_percent10 / 100)All 4 passes — pass 1 is the card above pass discount_percent1 10 2 10 3 10 4 150 final_price ← 90.0
60try:61 final_price→ 90.0 = calculate_discount(price100, discount10)62 print(f" ${price100} - {discount10}% = ${final_price90.0:.2f}")63except (TypeError, ValueError) as e:output $100 - 10% = $90.00if not isinstance(discount_percent, (int, float)):
42 raise TypeError(f"Price must be numeric, got {type(price).__name__}")43if not isinstance(discount_percent10, (int, float)):44 raise TypeError(f"Discount must be numeric, got {type(discount_percent10).__name__}")45if discount_percent < 0 or discount_percent > 100:except (TypeError, ValueError) as e:
pass 1 of 362 print(f" ${price} - {discount}% = ${final_price:.2f}")63except (TypeError, ValueError) as e:64 print(f" ${price100} - {discount10}%: {eDiscount must be numeric, got str}")output $100 - 10%: Discount must be numeric, got str $100 - 10%: Discount must be numeric, got strAll 3 passes — pass 1 is the card above pass discountediscount_percent1 10 Discount must be numeric, got str — 2 10 Price must be numeric, got str 150 3 150 Discount must be 0-100%, got 150 — if not isinstance(price, (int, float)):
40def calculate_discount(price, discount_percent):41 if not isinstance(price100, (int, float)):42 raise TypeError(f"Price must be numeric, got {type(price100).__name__}")43 if not isinstance(discount_percent, (int, float)):if discount_percent < 0 or discount_percent > 100:
44 raise TypeError(f"Discount must be numeric, got {type(discount_percent).__name__}")45if discount_percent150 < 0 or discount_percent > 100:46 raise ValueError(f"Discount must be 0-100%, got {discount_percent150}")fruits ← ['apple', 'banana', 'cherry'], indices ← [0, 5, -1, '2']
76print("\nList access:")7778fruits→ ['apple', 'banana', 'cherry'] = ["apple", "banana", "cherry"]79indices→ [0, 5, -1, '2'] = [0, 5, -1, "2"]output List access:for idx in indices:
pass 1 of 481for idx0 in indices[0, 5, -1, '2']:82 try:83 fruit = get_item(fruits, idx)All 4 passes — pass 1 is the card above pass idxindexitems1 0 — — 2 5 5 ['apple', 'banana', 'cherry'] 3 -1 -1 — 4 2 2 — try:
pass 1 of 481for idx in indices:82 try:83 fruit = get_item(fruits['apple', 'banana', 'cherry'], idx0)84 print(f" fruits[{idx}] = {fruit}")All 4 passes — pass 1 is the card above pass idxindexitems1 0 — — 2 5 5 ['apple', 'banana', 'cherry'] 3 -1 -1 — 4 2 2 — def get_item(items, index):
pass 1 of 466# Index validation with context67def get_item(items['apple', 'banana', 'cherry'], index0):68 if not isinstance(index, int):69 raise TypeError(f"Index must be integer, got {type(index).__name__}")70 if index < 0:71 raise IndexError(f"Index must be non-negative, got {index}")72 if index >= len(items):73 raise IndexError(f"Index {index} out of range (list size: {len(items)})")74 return items[index]appleAll 4 passes — pass 1 is the card above pass indexitems[index]1 0 apple 2 5 — 3 -1 — 4 2 — fruit ← apple
82try:83 fruit→ apple = get_item(fruits['apple', 'banana', 'cherry'], idx0)84 print(f" fruits[{idx0}] = {fruitapple}")85except (TypeError, IndexError) as e:output fruits[0] = appleif index >= len(items):
71 raise IndexError(f"Index must be non-negative, got {index}")72if index5 >= len(items['apple', 'banana', 'cherry']):73 raise IndexError(f"Index {index5} out of range (list size: {len(items['apple', 'banana', 'cherry'])})")74return items[index]except (TypeError, IndexError) as e:
pass 1 of 384 print(f" fruits[{idx}] = {fruit}")85except (TypeError, IndexError) as e:86 print(f" fruits[{idx5}]: {eIndex 5 out of range (list size: 3)}")output fruits[5]: Index 5 out of range (list size: 3) fruits[5]: Index 5 out of range (list size: 3)All 3 passes — pass 1 is the card above pass idxeindex1 5 Index 5 out of range (list size: 3) -1 2 -1 Index must be non-negative, got -1 2 3 2 Index must be integer, got str — if index < 0:
69 raise TypeError(f"Index must be integer, got {type(index).__name__}")70if index-1 < 0:71 raise IndexError(f"Index must be non-negative, got {index-1}")72if index >= len(items):if not isinstance(index, int):
67def get_item(items, index):68 if not isinstance(index2, int):69 raise TypeError(f"Index must be integer, got {type(index2).__name__}")70 if index < 0:main()
88if __name__ == "__main__":89 main()
Include the problematic value: raise ValueError(f"Invalid age: {age}").
Re-raise current exception
Catch, do something, then let it propagate.
# Re-raising exceptions after logging
def main():
# Log and re-raise
def process_payment(amount):
if amount <= 0:
raise ValueError("Amount must be positive")
print(f" Processing payment: ${amount}")
return {"status": "success", "amount": amount}
def handle_payment(amount):
try:
return process_payment(amount)
except ValueError as e:
print(f" [LOG] Payment failed: {e}")
raise # Re-raise the same exception
print("Payment processing:\n")
try:
result = handle_payment(100)
print(f"Result: {result}")
except ValueError as e:
print(f"Main caught: {e}")
print()
try:
result = handle_payment(-50)
print(f"Result: {result}")
except ValueError as e:
print(f"Main caught: {e}")
# Cleanup and re-raise
def database_operation(query):
connection = "DB_CONNECTION"
print(f" Opened: {connection}")
try:
if "invalid" in query:
raise RuntimeError(f"Bad query: {query}")
print(f" Executed: {query}")
return "RESULT"
except RuntimeError:
print(f" Error occurred, cleaning up...")
print(f" Closed: {connection}")
raise # Re-raise after cleanup
finally:
# This runs regardless
pass
print("\nDatabase operations:")
try:
result = database_operation("SELECT * FROM users")
print(f" Success: {result}\n")
except RuntimeError as e:
print(f" Failed: {e}\n")
try:
result = database_operation("invalid syntax")
print(f" Success: {result}")
except RuntimeError as e:
print(f" Failed: {e}")
# Conditional re-raise
def validate_and_parse(data):
try:
value = int(data)
if value < 0:
raise ValueError("Value must be non-negative")
return value
except ValueError as e:
if "invalid literal" in str(e):
# Handle parse errors locally
print(f" Parse error, using default")
return 0
else:
# Re-raise validation errors
raise
print("\nValidation and parsing:")
test_data = ["42", "abc", "-10"]
for data in test_data:
try:
result = validate_and_parse(data)
print(f" '{data}' → {result}")
except ValueError as e:
print(f" '{data}' → Error: {e}")
# Transform and re-raise
def risky_operation():
items = [1, 2, 3]
return items[10] # IndexError
def wrapped_operation():
try:
return risky_operation()
except IndexError as e:
print(f" [LOG] IndexError: {e}")
# Could transform exception type here
raise RuntimeError("Operation failed") from e
print("\nWrapped operation:")
try:
wrapped_operation()
except RuntimeError as e:
print(f" Caught RuntimeError: {e}")
print(f" Caused by: {e.__cause__}")
if __name__ == "__main__":
main()
# Re-raising exceptions after logging
def main():
# Log and re-raise
def process_payment(amount):
if amount <= 0:
raise ValueError("Amount must be positive")
print(f" Processing payment: ${amount}")
return {"status": "success", "amount": amount}
def handle_payment(amount):
try:
return process_payment(amount)
except ValueError as e:
print(f" [LOG] Payment failed: {e}")
raise # Re-raise the same exception
print("Payment processing:\n")
try:
result = handle_payment(100)
print(f"Result: {result}")
except ValueError as e:
print(f"Main caught: {e}")
print()
try:
result = handle_payment(-50)
print(f"Result: {result}")
except ValueError as e:
print(f"Main caught: {e}")
# Cleanup and re-raise
def database_operation(query):
connection = "DB_CONNECTION"
print(f" Opened: {connection}")
try:
if "invalid" in query:
raise RuntimeError(f"Bad query: {query}")
print(f" Executed: {query}")
return "RESULT"
except RuntimeError:
print(f" Error occurred, cleaning up...")
print(f" Closed: {connection}")
raise # Re-raise after cleanup
finally:
# This runs regardless
pass
print("\nDatabase operations:")
try:
result = database_operation("SELECT * FROM users")
print(f" Success: {result}\n")
except RuntimeError as e:
print(f" Failed: {e}\n")
try:
result = database_operation("invalid syntax")
print(f" Success: {result}")
except RuntimeError as e:
print(f" Failed: {e}")
# Conditional re-raise
def validate_and_parse(data):
try:
value = int(data)
if value < 0:
raise ValueError("Value must be non-negative")
return value
except ValueError as e:
if "invalid literal" in str(e):
# Handle parse errors locally
print(f" Parse error, using default")
return 0
else:
# Re-raise validation errors
raise
print("\nValidation and parsing:")
test_data = ["10", "xyz", "-5"]
for data in test_data:
try:
result = validate_and_parse(data)
print(f" '{data}' → {result}")
except ValueError as e:
print(f" '{data}' → Error: {e}")
# Transform and re-raise
def risky_operation():
items = [1, 2, 3]
return items[10] # IndexError
def wrapped_operation():
try:
return risky_operation()
except IndexError as e:
print(f" [LOG] IndexError: {e}")
# Could transform exception type here
raise RuntimeError("Operation failed") from e
print("\nWrapped operation:")
try:
wrapped_operation()
except RuntimeError as e:
print(f" Caught RuntimeError: {e}")
print(f" Caused by: {e.__cause__}")
if __name__ == "__main__":
main()
# Re-raising exceptions after logging
def main():
# Log and re-raise
def process_payment(amount):
if amount <= 0:
raise ValueError("Amount must be positive")
print(f" Processing payment: ${amount}")
return {"status": "success", "amount": amount}
def handle_payment(amount):
try:
return process_payment(amount)
except ValueError as e:
print(f" [LOG] Payment failed: {e}")
raise # Re-raise the same exception
print("Payment processing:\n")
try:
result = handle_payment(100)
print(f"Result: {result}")
except ValueError as e:
print(f"Main caught: {e}")
print()
try:
result = handle_payment(-50)
print(f"Result: {result}")
except ValueError as e:
print(f"Main caught: {e}")
# Cleanup and re-raise
def database_operation(query):
connection = "DB_CONNECTION"
print(f" Opened: {connection}")
try:
if "invalid" in query:
raise RuntimeError(f"Bad query: {query}")
print(f" Executed: {query}")
return "RESULT"
except RuntimeError:
print(f" Error occurred, cleaning up...")
print(f" Closed: {connection}")
raise # Re-raise after cleanup
finally:
# This runs regardless
pass
print("\nDatabase operations:")
try:
result = database_operation("SELECT * FROM users")
print(f" Success: {result}\n")
except RuntimeError as e:
print(f" Failed: {e}\n")
try:
result = database_operation("invalid syntax")
print(f" Success: {result}")
except RuntimeError as e:
print(f" Failed: {e}")
# Conditional re-raise
def validate_and_parse(data):
try:
value = int(data)
if value < 0:
raise ValueError("Value must be non-negative")
return value
except ValueError as e:
if "invalid literal" in str(e):
# Handle parse errors locally
print(f" Parse error, using default")
return 0
else:
# Re-raise validation errors
raise
print("\nValidation and parsing:")
test_data = ["100", "0", "abc"]
for data in test_data:
try:
result = validate_and_parse(data)
print(f" '{data}' → {result}")
except ValueError as e:
print(f" '{data}' → Error: {e}")
# Transform and re-raise
def risky_operation():
items = [1, 2, 3]
return items[10] # IndexError
def wrapped_operation():
try:
return risky_operation()
except IndexError as e:
print(f" [LOG] IndexError: {e}")
# Could transform exception type here
raise RuntimeError("Operation failed") from e
print("\nWrapped operation:")
try:
wrapped_operation()
except RuntimeError as e:
print(f" Caught RuntimeError: {e}")
print(f" Caused by: {e.__cause__}")
if __name__ == "__main__":
main()
def main(): # Log and re-raise
3def main():4 # Log and re-raise5 def process_payment(amount):6 if amount <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount}")9 return {"status": "success", "amount": amount}10 11 def handle_payment(amount):12 try:13 return process_payment(amount)14 except ValueError as e:15 print(f" [LOG] Payment failed: {e}")16 raise # Re-raise the same exception17 18 print("Payment processing:\n")outputPayment processing:def handle_payment(amount):
pass 1 of 211def handle_payment(amount100):12 try:13 return process_payment(amount)try:
pass 1 of 211def handle_payment(amount):12 try:13 return process_payment(amount100)14 except ValueError as e:def process_payment(amount):
pass 1 of 24# Log and re-raise5def process_payment(amount100):6 if amount <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount100}")9 return {"status": "success", "amount": amount100}output Processing payment: $100result ← {'status': 'success', 'amount': 100}
20try:21 result→ {'status': 'success', 'amount': 100} = handle_payment(100)22 print(f"Result: {result{'status': 'success', 'amount': 100}}")23except ValueError as e:outputResult: {'status': 'success', 'amount': 100}print()
26print()def handle_payment(amount):
pass 2 of 211def handle_payment(amount-50):12 try:13 return process_payment(amount)try:
pass 2 of 211def handle_payment(amount):12 try:13 return process_payment(amount-50)14 except ValueError as e:def process_payment(amount):
pass 2 of 24# Log and re-raise5def process_payment(amount-50):6 if amount <= 0:7 raise ValueError("Amount must be positive")if amount <= 0:
5def process_payment(amount):6 if amount-50 <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount}")except ValueError as e:
13 return process_payment(amount)14except ValueError as e:15 print(f" [LOG] Payment failed: {eAmount must be positive}")16 raise # Re-raise the same exceptionoutput [LOG] Payment failed: Amount must be positiveexcept ValueError as e:
30 print(f"Result: {result}")31except ValueError as e:32 print(f"Main caught: {eAmount must be positive}")3334#@help h1outputMain caught: Amount must be positive Main caught: Amount must be positiveprint(" Database operations:")
58print("\nDatabase operations:")output Database operations:connection ← DB_CONNECTION
pass 1 of 240# Cleanup and re-raise41def database_operation(querySELECT * FROM users):42 connection→ DB_CONNECTION = "DB_CONNECTION"43 print(f" Opened: {connectionDB_CONNECTION}")output Opened: DB_CONNECTIONtry:
pass 1 of 245try:46 if "invalid" in query:47 raise RuntimeError(f"Bad query: {query}")48 print(f" Executed: {querySELECT * FROM users}")49 return "RESULT"50except RuntimeError:output Executed: SELECT * FROM usersresult ← RESULT
60try:61 result→ RESULT = database_operation("SELECT * FROM users")62 print(f" Success: {resultRESULT}\n")63except RuntimeError as e:output Success: RESULTconnection ← DB_CONNECTION
pass 2 of 240# Cleanup and re-raise41def database_operation(queryinvalid syntax):42 connection→ DB_CONNECTION = "DB_CONNECTION"43 print(f" Opened: {connectionDB_CONNECTION}")output Opened: DB_CONNECTIONtry:
pass 2 of 245try:46 if "invalid" in query:47 raise RuntimeError(f"Bad query: {query}")if "invalid" in query:
45try:46 if "invalid" in queryinvalid syntax:47 raise RuntimeError(f"Bad query: {queryinvalid syntax}")48 print(f" Executed: {query}")except RuntimeError:
49 return "RESULT"50except RuntimeError:51 print(f" Error occurred, cleaning up...")52 print(f" Closed: {connectionDB_CONNECTION}")53 raise # Re-raise after cleanup54finally:output Error occurred, cleaning up... Closed: DB_CONNECTIONexcept RuntimeError as e:
68 print(f" Success: {result}")69except RuntimeError as e:70 print(f" Failed: {eBad query: invalid syntax}")7172# Conditional re-raiseoutput Failed: Bad query: invalid syntax Failed: Bad query: invalid syntaxtest_data ← ['42', 'abc', '-10']
88print("\nValidation and parsing:")8990test_data→ ['42', 'abc', '-10'] = ["42", "abc", "-10"]91#@test_data=["10", "xyz", "-5"], ["100", "0", "abc"]output Validation and parsing:for data in test_data:
pass 1 of 393for data42 in test_data['42', 'abc', '-10']:94 try:95 result = validate_and_parse(data)All 3 passes — pass 1 is the card above pass dataevalue1 42 — — 2 abc invalid literal for int() with base 10: 'abc' — 3 -10 Value must be non-negative -10 try:
pass 1 of 393for data in test_data:94 try:95 result = validate_and_parse(data42)96 print(f" '{data}' → {result}")All 3 passes — pass 1 is the card above pass dataevalue1 42 — — 2 abc invalid literal for int() with base 10: 'abc' — 3 -10 Value must be non-negative -10 def validate_and_parse(data):
pass 1 of 372# Conditional re-raise73def validate_and_parse(data42):74 try:75 value = int(data)All 3 passes — pass 1 is the card above pass dataevalue1 42 — — 2 abc invalid literal for int() with base 10: 'abc' — 3 -10 Value must be non-negative -10 value ← 42
pass 1 of 373def validate_and_parse(data):74 try:75 value→ 42 = int(data42)76 if value < 0:77 raise ValueError("Value must be non-negative")78 return value4279 except ValueError as e:All 3 passes — pass 1 is the card above pass dataevalue1 42 — 42 2 abc invalid literal for int() with base 10: 'abc' — 3 -10 Value must be non-negative -10 result ← 42
94try:95 result→ 42 = validate_and_parse(data42)96 print(f" '{data42}' → {result42}")97except ValueError as e:output '42' → 42if "invalid literal" in str(e): # Handle parse errors …
79except ValueError as e:80 if "invalid literal" in str(einvalid literal for int() with base 10: 'abc'):81 # Handle parse errors locally82 print(f" Parse error, using default")83 return 084 else:output Parse error, using defaultresult ← 0
94try:95 result→ 0 = validate_and_parse(dataabc)96 print(f" '{dataabc}' → {result0}")97except ValueError as e:output 'abc' → 0if value < 0:
75value = int(data)76if value-10 < 0:77 raise ValueError("Value must be non-negative")78return valueexcept ValueError as e:
96 print(f" '{data}' → {result}")97except ValueError as e:98 print(f" '{data-10}' → Error: {eValue must be non-negative}")output '-10' → Error: Value must be non-negative '-10' → Error: Value must be non-negativeprint(" Wrapped operation:")
113print("\nWrapped operation:")output Wrapped operation:items ← [1, 2, 3]
100# Transform and re-raise101def risky_operation():102 items→ [1, 2, 3] = [1, 2, 3]103 return items[10](empty) # IndexErrorexcept IndexError as e:
107 return risky_operation()108except IndexError as e:109 print(f" [LOG] IndexError: {elist index out of range}")110 # Could transform exception type here111 raise RuntimeError("Operation failed") from elist index out of rangeoutput [LOG] IndexError: list index out of rangeexcept RuntimeError as e:
116 wrapped_operation()117except RuntimeError as e:118 print(f" Caught RuntimeError: {eOperation failed}")119 print(f" Caused by: {e.__cause__list index out of range}")output Caught RuntimeError: Operation failed Caused by: list index out of range Caused by: list index out of rangemain()
121if __name__ == "__main__":122 main()
def main(): # Log and re-raise
3def main():4 # Log and re-raise5 def process_payment(amount):6 if amount <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount}")9 return {"status": "success", "amount": amount}10 11 def handle_payment(amount):12 try:13 return process_payment(amount)14 except ValueError as e:15 print(f" [LOG] Payment failed: {e}")16 raise # Re-raise the same exception17 18 print("Payment processing:\n")outputPayment processing:def handle_payment(amount):
pass 1 of 211def handle_payment(amount100):12 try:13 return process_payment(amount)try:
pass 1 of 211def handle_payment(amount):12 try:13 return process_payment(amount100)14 except ValueError as e:def process_payment(amount):
pass 1 of 24# Log and re-raise5def process_payment(amount100):6 if amount <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount100}")9 return {"status": "success", "amount": amount100}output Processing payment: $100result ← {'status': 'success', 'amount': 100}
20try:21 result→ {'status': 'success', 'amount': 100} = handle_payment(100)22 print(f"Result: {result{'status': 'success', 'amount': 100}}")23except ValueError as e:outputResult: {'status': 'success', 'amount': 100}print()
26print()def handle_payment(amount):
pass 2 of 211def handle_payment(amount-50):12 try:13 return process_payment(amount)try:
pass 2 of 211def handle_payment(amount):12 try:13 return process_payment(amount-50)14 except ValueError as e:def process_payment(amount):
pass 2 of 24# Log and re-raise5def process_payment(amount-50):6 if amount <= 0:7 raise ValueError("Amount must be positive")if amount <= 0:
5def process_payment(amount):6 if amount-50 <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount}")except ValueError as e:
13 return process_payment(amount)14except ValueError as e:15 print(f" [LOG] Payment failed: {eAmount must be positive}")16 raise # Re-raise the same exceptionoutput [LOG] Payment failed: Amount must be positiveexcept ValueError as e:
30 print(f"Result: {result}")31except ValueError as e:32 print(f"Main caught: {eAmount must be positive}")33outputMain caught: Amount must be positive Main caught: Amount must be positiveprint(" Database operations:")
53print("\nDatabase operations:")output Database operations:connection ← DB_CONNECTION
pass 1 of 235# Cleanup and re-raise36def database_operation(querySELECT * FROM users):37 connection→ DB_CONNECTION = "DB_CONNECTION"38 print(f" Opened: {connectionDB_CONNECTION}")output Opened: DB_CONNECTIONtry:
pass 1 of 240try:41 if "invalid" in query:42 raise RuntimeError(f"Bad query: {query}")43 print(f" Executed: {querySELECT * FROM users}")44 return "RESULT"45except RuntimeError:output Executed: SELECT * FROM usersresult ← RESULT
55try:56 result→ RESULT = database_operation("SELECT * FROM users")57 print(f" Success: {resultRESULT}\n")58except RuntimeError as e:output Success: RESULTconnection ← DB_CONNECTION
pass 2 of 235# Cleanup and re-raise36def database_operation(queryinvalid syntax):37 connection→ DB_CONNECTION = "DB_CONNECTION"38 print(f" Opened: {connectionDB_CONNECTION}")output Opened: DB_CONNECTIONtry:
pass 2 of 240try:41 if "invalid" in query:42 raise RuntimeError(f"Bad query: {query}")if "invalid" in query:
40try:41 if "invalid" in queryinvalid syntax:42 raise RuntimeError(f"Bad query: {queryinvalid syntax}")43 print(f" Executed: {query}")except RuntimeError:
44 return "RESULT"45except RuntimeError:46 print(f" Error occurred, cleaning up...")47 print(f" Closed: {connectionDB_CONNECTION}")48 raise # Re-raise after cleanup49finally:output Error occurred, cleaning up... Closed: DB_CONNECTIONexcept RuntimeError as e:
63 print(f" Success: {result}")64except RuntimeError as e:65 print(f" Failed: {eBad query: invalid syntax}")6667# Conditional re-raiseoutput Failed: Bad query: invalid syntax Failed: Bad query: invalid syntaxtest_data ← ['10', 'xyz', '-5']
83print("\nValidation and parsing:")8485test_data→ ['10', 'xyz', '-5'] = ["10", "xyz", "-5"]output Validation and parsing:for data in test_data:
pass 1 of 387for data10 in test_data['10', 'xyz', '-5']:88 try:89 result = validate_and_parse(data)All 3 passes — pass 1 is the card above pass dataevalue1 10 — — 2 xyz invalid literal for int() with base 10: 'xyz' — 3 -5 Value must be non-negative -5 try:
pass 1 of 387for data in test_data:88 try:89 result = validate_and_parse(data10)90 print(f" '{data}' → {result}")All 3 passes — pass 1 is the card above pass dataevalue1 10 — — 2 xyz invalid literal for int() with base 10: 'xyz' — 3 -5 Value must be non-negative -5 def validate_and_parse(data):
pass 1 of 367# Conditional re-raise68def validate_and_parse(data10):69 try:70 value = int(data)All 3 passes — pass 1 is the card above pass dataevalue1 10 — — 2 xyz invalid literal for int() with base 10: 'xyz' — 3 -5 Value must be non-negative -5 value ← 10
pass 1 of 368def validate_and_parse(data):69 try:70 value→ 10 = int(data10)71 if value < 0:72 raise ValueError("Value must be non-negative")73 return value1074 except ValueError as e:All 3 passes — pass 1 is the card above pass dataevalue1 10 — 10 2 xyz invalid literal for int() with base 10: 'xyz' — 3 -5 Value must be non-negative -5 result ← 10
88try:89 result→ 10 = validate_and_parse(data10)90 print(f" '{data10}' → {result10}")91except ValueError as e:output '10' → 10if "invalid literal" in str(e): # Handle parse errors …
74except ValueError as e:75 if "invalid literal" in str(einvalid literal for int() with base 10: 'xyz'):76 # Handle parse errors locally77 print(f" Parse error, using default")78 return 079 else:output Parse error, using defaultresult ← 0
88try:89 result→ 0 = validate_and_parse(dataxyz)90 print(f" '{dataxyz}' → {result0}")91except ValueError as e:output 'xyz' → 0if value < 0:
70value = int(data)71if value-5 < 0:72 raise ValueError("Value must be non-negative")73return valueexcept ValueError as e:
90 print(f" '{data}' → {result}")91except ValueError as e:92 print(f" '{data-5}' → Error: {eValue must be non-negative}")output '-5' → Error: Value must be non-negative '-5' → Error: Value must be non-negativeprint(" Wrapped operation:")
107print("\nWrapped operation:")output Wrapped operation:items ← [1, 2, 3]
94# Transform and re-raise95def risky_operation():96 items→ [1, 2, 3] = [1, 2, 3]97 return items[10](empty) # IndexErrorexcept IndexError as e:
101 return risky_operation()102except IndexError as e:103 print(f" [LOG] IndexError: {elist index out of range}")104 # Could transform exception type here105 raise RuntimeError("Operation failed") from elist index out of rangeoutput [LOG] IndexError: list index out of rangeexcept RuntimeError as e:
110 wrapped_operation()111except RuntimeError as e:112 print(f" Caught RuntimeError: {eOperation failed}")113 print(f" Caused by: {e.__cause__list index out of range}")output Caught RuntimeError: Operation failed Caused by: list index out of range Caused by: list index out of rangemain()
115if __name__ == "__main__":116 main()
def main(): # Log and re-raise
3def main():4 # Log and re-raise5 def process_payment(amount):6 if amount <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount}")9 return {"status": "success", "amount": amount}10 11 def handle_payment(amount):12 try:13 return process_payment(amount)14 except ValueError as e:15 print(f" [LOG] Payment failed: {e}")16 raise # Re-raise the same exception17 18 print("Payment processing:\n")outputPayment processing:def handle_payment(amount):
pass 1 of 211def handle_payment(amount100):12 try:13 return process_payment(amount)try:
pass 1 of 211def handle_payment(amount):12 try:13 return process_payment(amount100)14 except ValueError as e:def process_payment(amount):
pass 1 of 24# Log and re-raise5def process_payment(amount100):6 if amount <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount100}")9 return {"status": "success", "amount": amount100}output Processing payment: $100result ← {'status': 'success', 'amount': 100}
20try:21 result→ {'status': 'success', 'amount': 100} = handle_payment(100)22 print(f"Result: {result{'status': 'success', 'amount': 100}}")23except ValueError as e:outputResult: {'status': 'success', 'amount': 100}print()
26print()def handle_payment(amount):
pass 2 of 211def handle_payment(amount-50):12 try:13 return process_payment(amount)try:
pass 2 of 211def handle_payment(amount):12 try:13 return process_payment(amount-50)14 except ValueError as e:def process_payment(amount):
pass 2 of 24# Log and re-raise5def process_payment(amount-50):6 if amount <= 0:7 raise ValueError("Amount must be positive")if amount <= 0:
5def process_payment(amount):6 if amount-50 <= 0:7 raise ValueError("Amount must be positive")8 print(f" Processing payment: ${amount}")except ValueError as e:
13 return process_payment(amount)14except ValueError as e:15 print(f" [LOG] Payment failed: {eAmount must be positive}")16 raise # Re-raise the same exceptionoutput [LOG] Payment failed: Amount must be positiveexcept ValueError as e:
30 print(f"Result: {result}")31except ValueError as e:32 print(f"Main caught: {eAmount must be positive}")33outputMain caught: Amount must be positive Main caught: Amount must be positiveprint(" Database operations:")
53print("\nDatabase operations:")output Database operations:connection ← DB_CONNECTION
pass 1 of 235# Cleanup and re-raise36def database_operation(querySELECT * FROM users):37 connection→ DB_CONNECTION = "DB_CONNECTION"38 print(f" Opened: {connectionDB_CONNECTION}")output Opened: DB_CONNECTIONtry:
pass 1 of 240try:41 if "invalid" in query:42 raise RuntimeError(f"Bad query: {query}")43 print(f" Executed: {querySELECT * FROM users}")44 return "RESULT"45except RuntimeError:output Executed: SELECT * FROM usersresult ← RESULT
55try:56 result→ RESULT = database_operation("SELECT * FROM users")57 print(f" Success: {resultRESULT}\n")58except RuntimeError as e:output Success: RESULTconnection ← DB_CONNECTION
pass 2 of 235# Cleanup and re-raise36def database_operation(queryinvalid syntax):37 connection→ DB_CONNECTION = "DB_CONNECTION"38 print(f" Opened: {connectionDB_CONNECTION}")output Opened: DB_CONNECTIONtry:
pass 2 of 240try:41 if "invalid" in query:42 raise RuntimeError(f"Bad query: {query}")if "invalid" in query:
40try:41 if "invalid" in queryinvalid syntax:42 raise RuntimeError(f"Bad query: {queryinvalid syntax}")43 print(f" Executed: {query}")except RuntimeError:
44 return "RESULT"45except RuntimeError:46 print(f" Error occurred, cleaning up...")47 print(f" Closed: {connectionDB_CONNECTION}")48 raise # Re-raise after cleanup49finally:output Error occurred, cleaning up... Closed: DB_CONNECTIONexcept RuntimeError as e:
63 print(f" Success: {result}")64except RuntimeError as e:65 print(f" Failed: {eBad query: invalid syntax}")6667# Conditional re-raiseoutput Failed: Bad query: invalid syntax Failed: Bad query: invalid syntaxtest_data ← ['100', '0', 'abc']
83print("\nValidation and parsing:")8485test_data→ ['100', '0', 'abc'] = ["100", "0", "abc"]output Validation and parsing:for data in test_data:
pass 1 of 387for data100 in test_data['100', '0', 'abc']:88 try:89 result = validate_and_parse(data)All 3 passes — pass 1 is the card above pass datae1 100 — 2 0 — 3 abc invalid literal for int() with base 10: 'abc' try:
pass 1 of 387for data in test_data:88 try:89 result = validate_and_parse(data100)90 print(f" '{data}' → {result}")All 3 passes — pass 1 is the card above pass datae1 100 — 2 0 — 3 abc invalid literal for int() with base 10: 'abc' def validate_and_parse(data):
pass 1 of 367# Conditional re-raise68def validate_and_parse(data100):69 try:70 value = int(data)All 3 passes — pass 1 is the card above pass datae1 100 — 2 0 — 3 abc invalid literal for int() with base 10: 'abc' value ← 100
pass 1 of 368def validate_and_parse(data):69 try:70 value→ 100 = int(data100)71 if value < 0:72 raise ValueError("Value must be non-negative")73 return value10074 except ValueError as e:All 3 passes — pass 1 is the card above pass dataevalue1 100 — 100 2 0 — 0 3 abc invalid literal for int() with base 10: 'abc' — result ← 100
88try:89 result→ 100 = validate_and_parse(data100)90 print(f" '{data100}' → {result100}")91except ValueError as e:output '100' → 100result ← 0
88try:89 result→ 0 = validate_and_parse(data0)90 print(f" '{data0}' → {result0}")91except ValueError as e:output '0' → 0if "invalid literal" in str(e): # Handle parse errors …
74except ValueError as e:75 if "invalid literal" in str(einvalid literal for int() with base 10: 'abc'):76 # Handle parse errors locally77 print(f" Parse error, using default")78 return 079 else:output Parse error, using defaultresult ← 0
88try:89 result→ 0 = validate_and_parse(dataabc)90 print(f" '{dataabc}' → {result0}")91except ValueError as e:output 'abc' → 0print(" Wrapped operation:")
107print("\nWrapped operation:")output Wrapped operation:items ← [1, 2, 3]
94# Transform and re-raise95def risky_operation():96 items→ [1, 2, 3] = [1, 2, 3]97 return items[10](empty) # IndexErrorexcept IndexError as e:
101 return risky_operation()102except IndexError as e:103 print(f" [LOG] IndexError: {elist index out of range}")104 # Could transform exception type here105 raise RuntimeError("Operation failed") from elist index out of rangeoutput [LOG] IndexError: list index out of rangeexcept RuntimeError as e:
110 wrapped_operation()111except RuntimeError as e:112 print(f" Caught RuntimeError: {eOperation failed}")113 print(f" Caused by: {e.__cause__list index out of range}")output Caught RuntimeError: Operation failed Caused by: list index out of range Caused by: list index out of rangemain()
115if __name__ == "__main__":116 main()
Bare raise in except block re-raises the current exception.
Exception chaining
Preserve original exception when raising a new one.
# Exception chaining with 'from'
def main():
# Chain exceptions with 'from'
def load_config():
config_data = {"port": "invalid"}
try:
port = int(config_data["port"])
return port
except ValueError as e:
# Chain new exception from original
raise RuntimeError("Config load failed") from e
print("Exception chaining:\n")
try:
port = load_config()
print(f"Port: {port}")
except RuntimeError as e:
print(f"Exception: {e}")
print(f"Caused by: {e.__cause__}")
print(f"Cause type: {type(e.__cause__).__name__}")
# Multiple layers of chaining
def parse_number(text):
try:
return int(text)
except ValueError as e:
raise TypeError("Not a number") from e
def process_input(text):
try:
num = parse_number(text)
return num * 2
except TypeError as e:
raise RuntimeError("Processing failed") from e
print("\nMulti-layer chaining:")
try:
result = process_input("abc")
print(f"Result: {result}")
except RuntimeError as e:
print(f"Final exception: {e}")
print(f"Direct cause: {e.__cause__}")
print(f"Root cause: {e.__cause__.__cause__}")
# Suppress exception chaining
def operation_with_fallback():
try:
result = 10 / 0
except ZeroDivisionError:
# Suppress chain with 'from None'
raise ValueError("Invalid operation") from None
print("\nSuppressed chain:")
try:
operation_with_fallback()
except ValueError as e:
print(f"Exception: {e}")
print(f"Has cause: {e.__cause__ is not None}")
# Practical example: data pipeline
def fetch_data(source):
if source == "database":
raise ConnectionError("Database unreachable")
return None
def transform_data(data):
if data is None:
raise ValueError("No data to transform")
return data.upper()
def save_results(data):
if not data:
raise IOError("Cannot save empty data")
return "SAVED"
def run_pipeline(source):
try:
try:
data = fetch_data(source)
except ConnectionError as e:
raise RuntimeError("Fetch stage failed") from e
try:
transformed = transform_data(data)
except ValueError as e:
raise RuntimeError("Transform stage failed") from e
try:
result = save_results(transformed)
except IOError as e:
raise RuntimeError("Save stage failed") from e
return result
except RuntimeError:
raise
print("\nPipeline execution:")
try:
run_pipeline("database")
except RuntimeError as e:
print(f"Pipeline failed: {e}")
if e.__cause__:
print(f" Root cause: {type(e.__cause__).__name__}: {e.__cause__}")
# Check exception context
def analyze_exception(exc):
print(f"\nException analysis:")
print(f" Type: {type(exc).__name__}")
print(f" Message: {exc}")
if exc.__cause__:
print(f" Has cause: Yes")
print(f" Cause: {type(exc.__cause__).__name__}: {exc.__cause__}")
else:
print(f" Has cause: No")
try:
raise ValueError("Top level") from TypeError("Bottom level")
except ValueError as e:
analyze_exception(e)
if __name__ == "__main__":
main()
def main(): # Chain exceptions with 'from'
3def main():4 # Chain exceptions with 'from'5 def load_config():6 config_data = {"port": "invalid"}7 8 try:9 port = int(config_data["port"])10 return port11 except ValueError as e:12 # Chain new exception from original13 raise RuntimeError("Config load failed") from e14 15 print("Exception chaining:\n")outputException chaining:config_data ← {'port': 'invalid'}
4# Chain exceptions with 'from'5def load_config():6 config_data→ {'port': 'invalid'} = {"port": "invalid"}try:
8try:9 port = int(config_data["port"]invalid)10 return portexcept ValueError as e: # Chain new exception from origina…
10 return port11except ValueError as e:12 # Chain new exception from original13 raise RuntimeError("Config load failed") from einvalid literal for int() with base 10: 'invalid'except RuntimeError as e:
19 print(f"Port: {port}")20except RuntimeError as e:21 print(f"Exception: {eConfig load failed}")22 print(f"Caused by: {e.__cause__invalid literal for int() with base 10: 'invalid'}")23 print(f"Cause type: {type(e.__cause__invalid literal for int() with base 10: 'invalid').__name__}")2425#@help h1outputException: Config load failed Caused by: invalid literal for int() with base 10: 'invalid' Cause type: ValueError Cause type: ValueErrorprint(" Multi-layer chaining:")
45print("\nMulti-layer chaining:")output Multi-layer chaining:def process_input(text):
38def process_input(textabc):39 try:40 num = parse_number(text)try:
38def process_input(text):39 try:40 num = parse_number(textabc)41 return num * 2def parse_number(text):
31# Multiple layers of chaining32def parse_number(textabc):33 try:34 return int(text)try:
32def parse_number(text):33 try:34 return int(textabc)35 except ValueError as e:except ValueError as e:
34 return int(text)35except ValueError as e:36 raise TypeError("Not a number") from einvalid literal for int() with base 10: 'abc'except TypeError as e:
41 return num * 242except TypeError as e:43 raise RuntimeError("Processing failed") from eNot a numberexcept RuntimeError as e:
49 print(f"Result: {result}")50except RuntimeError as e:51 print(f"Final exception: {eProcessing failed}")52 print(f"Direct cause: {e.__cause__Not a number}")53 print(f"Root cause: {e.__cause__.__cause__invalid literal for int() with base 10: 'abc'}")5455# Suppress exception chainingoutputFinal exception: Processing failed Direct cause: Not a number Root cause: invalid literal for int() with base 10: 'abc' Root cause: invalid literal for int() with base 10: 'abc'print(" Suppressed chain:")
63print("\nSuppressed chain:")output Suppressed chain:except ValueError as e:
66 operation_with_fallback()67except ValueError as e:68 print(f"Exception: {eInvalid operation}")69 print(f"Has cause: {e.__cause__None is not None}")7071# Practical example: data pipelineoutputException: Invalid operation Has cause: False Has cause: Falseprint(" Pipeline execution:")
108print("\nPipeline execution:")output Pipeline execution:def run_pipeline(source):
87def run_pipeline(sourcedatabase):88 try:89 try:try:
88try:89 try:90 data = fetch_data(sourcedatabase)91 except ConnectionError as e:def fetch_data(source):
71# Practical example: data pipeline72def fetch_data(sourcedatabase):73 if source == "database":74 raise ConnectionError("Database unreachable")if source == "database":
72def fetch_data(source):73 if sourcedatabase == "database":74 raise ConnectionError("Database unreachable")75 return Noneexcept ConnectionError as e:
90 data = fetch_data(source)91except ConnectionError as e:92 raise RuntimeError("Fetch stage failed") from eDatabase unreachableexcept RuntimeError as e:
111 run_pipeline("database")112except RuntimeError as e:113 print(f"Pipeline failed: {eFetch stage failed}")114 if e.__cause__:outputPipeline failed: Fetch stage failedif e.__cause__:
113 print(f"Pipeline failed: {e}")114 if e.__cause__Database unreachable:115 print(f" Root cause: {type(e.__cause__Database unreachable).__name__}: {e.__cause__}")116117# Check exception contextoutput Root cause: ConnectionError: Database unreachable Root cause: ConnectionError: Database unreachableexcept ValueError as e:
130 raise ValueError("Top level") from TypeError("Bottom level")131except ValueError as e:132 analyze_exception(eTop level)def analyze_exception(exc):
117# Check exception context118def analyze_exception(excTop level):119 print(f"\nException analysis:")120 print(f" Type: {type(excTop level).__name__}")121 print(f" Message: {excTop level}")output Exception analysis: Type: ValueError Message: Top levelif exc.__cause__:
123if exc.__cause__Bottom level:124 print(f" Has cause: Yes")125 print(f" Cause: {type(exc.__cause__Bottom level).__name__}: {exc.__cause__}")126else:output Has cause: Yes Cause: TypeError: Bottom levelanalyze_exception(e)
131except ValueError as e:132 analyze_exception(eTop level)main()
134if __name__ == "__main__":135 main()
raise NewError() from original links exceptions together.
Exercise: practical.py
Build a validation system with proper exception raising