Definition
Dividing one number by another almost always has a result, except in one precise case: dividing by zero has no solution in mathematics, and Python cannot decide on your behalf what that result should be. Rather than invent a figure, it stops the calculation right there and raises the exception ZeroDivisionError.
Here is what that looks like when a headcount drops to zero:
headcount = 0 # nobody has been enrolled yet
total_marks = 240
average = total_marks / headcount
# ZeroDivisionError: division by zeroThe traceback points at the exact line, but not at where the zero came from, and that is precisely the question worth asking. A division by zero is rarely a mistake in the arithmetic: it is missing data, an empty list or a counter left at zero, that travelled through the program unnoticed up to that point.
ZeroDivisionError inherits from ArithmeticError, the class Python reserves for calculation errors. To catch several arithmetic errors at once, a division by zero and an overflow for instance, that parent class is the one to target in the except.
Three operators, one same refusal
Plain division is not the only one that hits this wall: floor division and the remainder of a division refuse in exactly the same way as soon as the divisor is zero. Only the operator used changes the sentence shown at the end of the message.
The table below sums up what you get depending on the operator and the type of numbers involved:
| Expression | Message obtained |
|---|---|
7 / 0 | division by zero |
7 // 0 | integer division or modulo by zero |
7 % 0 | integer modulo by zero |
7.0 / 0 | float division by zero |
0 / 0 | The same error, a zero dividend saves nothing |
That message is worth reading, because it states whether the calculation involved an int or a float, which often helps spot the guilty variable. Other languages hand back a silent infinity in this case, while Python stops everything: an error that shows up right away is far easier to spot than an infinity spreading into the calculations that follow.
Fixing it before it happens
Once a divisor can be zero, two solutions are available. The first checks the divisor before using it, the second lets the calculation run and catches the failure with try and except.
Here is the first approach:
def average(marks):
if not marks:
return None
return sum(marks) / len(marks)That version answers the real question an empty collection raises: an average with no marks does not exist, and None says so honestly. Going through len before dividing stays the most readable habit as soon as the divisor counts elements.
The second approach assumes instead that zero is a normal value, not an anomaly.
try:
rate = clicks / impressions
except ZeroDivisionError:
rate = 0.0 # no impression has happened yetCatching makes sense when zero is predictable and a fallback is reasonable, a click rate of nothing for instance. It makes less sense when that zero actually signals missing data: crushing the error under a 0.0 manufactures a false figure that will travel all the way to the dashboard without anyone noticing.
Writing a bare except: without naming ZeroDivisionError also catches errors that have nothing to do with it, a typo in a variable name for instance. The real bug then keeps existing, simply hidden behind a catch that was never meant for it.
The zero always comes from elsewhere
This error is fixed in a single line, which explains why it is so often fixed badly: adding a check or a catch treats the symptom, not the cause. The real work is tracing back to where that zero appeared.
The usual sources are few: a list emptied by an over-strict filter, a counter never incremented, an entry converted with no guard on it, or a column missing from an imported file. The calculation is not the culprit, it is only the messenger.
One simple rule spares long searches: when a divisor should never be zero, it is better to say so plainly with raise and an explicit message, rather than letting the calculation fail further down the code. The failure then happens in the right place, with the right variable name in front of you, and not three functions later.
Frequently asked questions
Why does Python refuse to hand back infinity?
Because no value truly satisfies the definition of a quotient by zero, and a silent infinity would then spread into every calculation that depends on it. The math module and the scientific computing libraries offer that behaviour when it is genuinely wanted, but it is never the default choice.
Should the divisor be checked, or the error caught?
Check when the zero is predictable and frequent, an empty collection for instance. Catch when it stays exceptional and unforeseen. A test placed right before the division usually reads better than a catching block, and it avoids swallowing an error coming from somewhere else in the code.
Can a very small decimal number trigger the same error?
No, dividing by 0.000001 works fine and hands back a huge but perfectly valid result. Only an exact zero causes the refusal, which makes some decimal calculations deceptive: a value brought down to zero by a misplaced round becomes, again, a forbidden divisor.