Modules & ErrorsLesson 3 of 3
Error Handling
The structure is almost identical: try/catch becomes try/except, throw becomes raise, and Error subclasses become Exception subclasses. You will adjust in minutes.
The real difference is Python's else clause on try blocks. The else block runs ONLY if no exception was raised, which is perfect for code that should execute after the risky operation succeeds but should not be inside the try block itself (so its own errors are not accidentally caught). JS has no equivalent.
Context managers (with statements) replace many try/finally patterns. Instead of opening a file, wrapping everything in try, and closing in finally, you write 'with open("file.txt") as f:' and the file closes automatically when the block ends. This pattern extends to database connections, locks, and any resource that needs cleanup.
A critical rule: never use a bare 'except:' without an exception type. It catches everything, including SystemExit (raised by sys.exit()) and KeyboardInterrupt (raised by Ctrl+C), so your program can swallow its own shutdown. At minimum, use 'except Exception:', which leaves those system-level exceptions alone.
Exception types form a hierarchy: BaseException at the top, Exception below it, and ValueError, TypeError, KeyError and friends below that. Catching a parent catches all of its children, so order your except blocks from most specific to most general, or the general one will swallow the specific ones. When you catch one error and raise another, write raise NewError(...) from err to keep the original as the cause, just like new Error(msg, { cause: err }) in JS.
Quick reference
| JavaScript | Python | Note |
|---|---|---|
| try { } catch (e) { } | try: ... except E as e: | except, not catch |
| throw new Error() | raise ValueError() | raise, not throw, no new |
| if (e instanceof X) | except X: | Type goes in the except clause |
| finally { } | finally: | Same concept |
| No equivalent | else: | Runs only if no exception |
| try/finally for cleanup | with statement | Auto-cleanup |
| new Error(msg, { cause }) | raise X(msg) from err | Exception chaining |
Side by side
// JavaScript
try {
JSON.parse(badJson);
throw new Error("Custom");
} catch (error) {
if (error instanceof SyntaxError)
console.log("JSON error");
} finally {
console.log("Cleanup");
}
class ValidationError extends Error {
constructor(field, msg) {
super(msg);
this.field = field;
}
}# Python
import json
try:
data = json.loads(bad_json)
except json.JSONDecodeError as e: # specific first
print(f"JSON error: {e}")
except ValueError as e: # then more general
print(f"Value error: {e}")
else: # no exception!
print("Parse succeeded")
finally:
print("Cleanup")
# Custom exception
class ValidationError(Exception):
def __init__(self, field, msg):
super().__init__(msg)
self.field = field
# Chaining: keep the original cause
try:
port = int("abc")
except ValueError as err:
raise ValidationError("port", "must be a number") from err
# Context manager (replaces try/finally)
with open("file.txt") as f:
content = f.read()
# auto-closed, even on error!Exercise
Real Python, running in your browserWrite a function called safe_divide:
Result: 2.5 Done
Ctrl + Enter runCtrl + Shift + Enter checkTab indentEsc then Tab to leave the editorCtrl + / comment