So far, when your code hit something it couldn't handle — dividing by zero, indexing past the end of a list, converting "abc" to an int — the program just crashed. Python printed a traceback and stopped.
That crash has a name: it's an exception. Python raises one every time it hits a runtime error it can't recover from on its own.
>>> 10 / 0
ZeroDivisionError: division by zero
Real programs deal with unreliable input all the time — a user types letters into a number field, a file doesn't exist, a network request times out. You don't want any of that to crash the whole program. Exceptions give you a way to catch the error and decide what happens next: show a friendly message, retry, fall back to a default — anything other than crashing.
Python ships with a hierarchy of built-in exception types, each describing a specific kind of failure:
ZeroDivisionError — division or modulo by zeroValueError — a value has the right type but an inappropriate value (e.g. int("abc"))TypeError — an operation got a value of the wrong typeIndexError — a sequence index is out of rangeKeyError — a dictionary key doesn't existKnowing the type matters because it's what lets you catch specific failures instead of blindly swallowing every possible error (which hides real bugs).
Next up: how to actually catch one.