Why this matters
A program that divides is trusting that the number it divides by is not zero. A shop divides the total bill by the number of items to get an average price. A game divides the distance travelled by the time taken to get a speed. A test score tool divides points earned by points possible. When the divisor is zero, the division has no answer, and the program has to decide what to do.
Python handles this the same way for every number type. A division by zero stops the program with ZeroDivisionError, whether the numbers are whole numbers or decimals. Some other languages return a special value for decimal numbers instead. Python does not do that by default, so the special values are something you create on purpose, and this lesson shows when that helps.
This lesson assumes you know the basic arithmetic operators and how Python reports an error. Results that are too big to fit in a fixed size are covered in the integer ranges lesson in this module.
What dividing by zero means
Start with a plain example. You have 10 apples and want to share them equally among 2 people. Each person gets 10 divided by 2, which is 5 apples. Division asks, "how many times does the second number fit into the first?"
Now try 10 apples shared among 0 people. The question is "how many times does 0 fit into 10?", and no number answers it. Zero people cannot receive any apples, so the question does not make sense. Mathematicians say the result is undefined. Undefined means there is no value the rules allow.
A computer cannot leave the answer undefined. It has to stop, return a special marker, or give a value that the program can check for. Python chooses to stop, and you choose whether to catch the stop.
Two words are used below. The number being divided is the dividend. The number it is divided by is the divisor. In 10 / 2, the dividend is 10 and the divisor is 2. A division by zero is a division where the divisor is 0.
Division by zero stops the program
The simplest program that divides by zero is this:
The first print runs, because it comes before the division. Then Python evaluates total / count. The divisor is 0, so Python raises an exception. An exception is an error signal that stops the normal flow of a program. When nothing in the program catches it, Python prints a report called a traceback and ends the program. Running the code above prints:
about to divide
Traceback (most recent call last):
File ".../average.py", line 4, in <module>
average = total / count
~~~~~~^~~~~~~
ZeroDivisionError: division by zeroEach part of this output has a meaning:
Traceback (most recent call last)says the error was not caught, and the list below it shows the calls that were active when it happened, with the newest last.File ".../average.py", line 4gives the file and the line where the error happened. Line 4 is the line withtotal / count. The path is shortened here, and your path shows the folder where you saved the file.- The line under the
Fileline copies the code, and the^and~marks show which part of the expression failed. ZeroDivisionErroris the name of the exception. The name says the error is about dividing by zero.division by zerois the message. It says the cause in plain words.
The program stopped on line 4, so line 5 never ran. The first line of output shows that the code before the division did run.
The error is not a flaw in Python. Python is refusing to produce a value that does not exist. The bug is in the program's logic: it divided without checking that the divisor was not zero.
Catching the error
Sometimes the program must keep going, even when a division fails. Python lets you catch an exception with a try block and an except block. The try block is the code that might raise the error. The except block is the code that runs when the named exception happens inside the try block. Here is the same division with an except:
caught: division by zero
program keeps runningWhen the division raises, Python jumps straight to the except block. The line that prints average is is skipped, because the value was never produced. The name error holds the exception object. Printing it shows the message.
The except block names ZeroDivisionError on purpose. An except names the exception it handles, and other errors pass through unchanged. If the name does not match the error, the error keeps going and stops the program as before.
Catching an error is not always the right fix. In the example above, the except block prints a message and then the program carries on without an average. That is fine for a demo, but a real program has to decide what the missing average means. The next section shows a cleaner way to avoid the error in the first place.
Check the divisor first
The cleanest form checks the divisor before the division. The check uses an if, and the division runs only when the divisor is not zero. Python's rule for a value that counts as false includes 0, so if count: is true only when count is not zero. Writing if count != 0: says the same thing more clearly.
2.5
NoneThe check comes before the division, so the division never runs with a zero divisor. The function returns None when the divisor is zero, which is a clear marker that the caller can test with is None.
Other operators that raise
The operators // and % also raise when the divisor is zero. On Python 3.14 they all print the same message. Older versions may word it differently, for example float division by zero:
10 // 0 raises division by zero
10 % 0 raises division by zero
10.0 / 0 raises division by zero
0.0 / 0.0 raises division by zeroThe function eval runs a text expression, and it is used here only so that the loop can show four cases. In your own code, write the expressions directly. The rule is the same for every number type in Python. int, float, // and % all raise ZeroDivisionError when the divisor is zero.
Decimal numbers do not give infinity by default
Many languages return Infinity or NaN (not a number) when a decimal number is divided by zero. Python raises the error instead, as the example above shows. The values still exist, and you can create them yourself with float("inf") and float("nan"). The standard math module, a built-in set of functions, also has math.inf and math.nan.
inf -inf True
nan
nan
False True
TrueThe rule for nan is that it is not equal to anything, including itself. nan == nan is False, and every <, >, <= and >= comparison with nan is also False. This means you cannot test for nan with ==. The function math.isnan is the right check. Infinity behaves as a value larger than every finite number, so inf > 10 ** 308 is True, and inf - inf is nan, because there is no single answer.
Once a value is nan, it spreads. Any arithmetic with a nan gives nan again. A single bad value can turn a whole calculation into nan, which is one reason to check for it early.
The decimal module behaves differently again. Its division by zero raises an exception that is named for the case, and 0 / 0 raises a different exception:
decimal: DivisionByZero
decimal 0/0: InvalidOperationThe decimal module is the choice for money. It raises an error instead of quietly giving inf or nan, which is the safer default for a payment total.
A worked example: averages
The average of a list of numbers is the sum divided by the count. It is a good place to see the choices. The program below has three versions of an average function. The first divides and lets the error happen, the second returns 0 for an empty list, and the third returns nan.
average of scores: 81.66666666666667
average_or_zero of scores: 81
average_or_nan of scores: 81.66666666666667
average_or_zero of empty: 0
average_or_nan of empty: nan
is nan: TrueThe first function, average, has no check. Calling it with an empty list raises ZeroDivisionError, and the program stops unless the caller catches the error. The second function returns 0 for an empty list. A later step might show a wrong average as if it were real, so the caller cannot tell an empty list from an average of 0. The integer division // drops the fraction, so 81.67 becomes 81. The third function returns nan, and the caller must check for it before using the value. Neither the second nor the third version is right for every program. The choice depends on what the caller expects. Write the choice down as part of the function's contract, which means the promise the function makes to its caller.
A progress bar: what the user sees
Averages are not the only place where a divisor can be zero. A progress bar on a download screen shows how much of the work is done, as a percentage of the total. When the total is zero, the percentage is undefined. This example has one function that works in whole numbers and one that works in decimals, and the output shows what a user would see in each case.
3 of 4: 75 %
1 of 3: 33 %
1 of 3 decimal: 33.333333333333336 %
5 of 0: 0 %
0 of 0 decimal: nan %The whole-number version gives 33 for one of three, because // drops the fraction. The decimal version gives 33.333333333333336, which is the closest float to one third, and that long tail is an artifact of how decimals are stored in binary. A screen usually rounds it, but the program has to choose where to round.
The percent_done function returns 0 when the total is zero. The screen then shows 0 %, which looks like a download that has not started. That may be wrong, because the total might be unknown, not zero. The decimal function returns nan, and the screen would show nan %. A user sees a clear sign of a bug, but the page looks broken.
If the same code is written without the check, the division stops the program with ZeroDivisionError: division by zero. For a web server, that stop means one request fails and the user sees an error page. For a desktop game, it means the program closes. Each choice has a cost, and the right one depends on what the user needs to know.
The three options compare as follows:
| Option | What the user sees | What can go wrong |
|---|---|---|
| Raise the error | The request fails or the program closes | The error is loud, but it stops work the user wanted |
| Return 0 | A number that looks like a real result | A wrong answer looks normal, and nobody notices |
Return nan | The text nan on screen | nan spreads into every later sum without an error |
None of the three is correct for every program. A payment total should not be 0 by accident, so raising an error or returning a clear marker is safer. A progress bar can show "unknown" instead of a number, which is a fourth option that needs its own check in the code.
Common mistakes
Checking the divisor after dividing. The condition if m / n == 0: divides first. When n is 0, the division raises before the if can test anything. The check must come before the division, as in if n != 0:.
Expecting inf from a division. 10 / 0.0 raises ZeroDivisionError in Python. It does not give inf, which you must create on purpose with float("inf").
Comparing with nan using ==. As shown above, x == float("nan") is always False, even when x is nan. Use math.isnan(x).
Catching the exception too broadly. A try block around a large part of the program can hide other bugs. Keep the try block small, around only the division that might fail, and name ZeroDivisionError in the except block. An except with no name catches every error, including ones you did not expect.
Naming the wrong exception. An except KeyError: block does not catch a division by zero. The error keeps going, and the program stops with the traceback as before. Name the exception that the code can raise.
Practice
Work each exercise yourself before you open the answer. Predict the output on paper first.
- What does this program print? Explain why.
x = 0.0
print(-3 / x)-
Which of these expressions raise
ZeroDivisionErrorwhen they run:5 / 0,5.0 / 0,0.0 / 0.0,0 / 0? Explain the rule in one sentence. -
Write a function
safe_divide(a, b)that returnsa / bwhenbis not zero and returns 0 whenbis zero. Then call it with the pairs(10, 0)and(10, 4). -
A program sets
ratiotox / ywhenyis not 0.0, and tofloat("nan")whenyis 0.0. Write a check that printsno ratiowhenratioisnan, and prints the value when it is a number. Usemath.isnan, not==. -
Why does this code still stop the program, even though it catches an exception? Fix it so the message prints and the program continues.
total = 8
count = 0
try:
print("start")
average = total / count
print("average is", average)
except KeyError:
print("caught")
print("done")Each exercise has an answer below a "Show the answer" line. Try each one first, then read the answer.
- The program raises
ZeroDivisionErroron the second line. The divisor is a float, but Python does not return-inffor a float division by zero.
Show the answer
Traceback (most recent call last):
...
ZeroDivisionError: division by zeroTo get negative infinity on purpose, write float("-inf") in the code.
-
5 / 0and0 / 0raise, and so do5.0 / 0and0.0 / 0.0. The rule is that every division with a zero divisor raises in Python, whatever the number types are. -
The check comes before the division.
Show the answer
def safe_divide(a, b):
if b == 0:
return 0
return a / b
print(safe_divide(10, 0))
print(safe_divide(10, 4))The output is 0 and then 2.5.
- Use
math.isnanon the result. The check prints the value only when it is a real number.
Show the answer
import math
x = 4.0
y = 0.0
if y == 0:
ratio = float("nan")
else:
ratio = x / y
if math.isnan(ratio):
print("no ratio")
else:
print("ratio is", ratio)The output is no ratio. Checking y == 0 before the division avoids the error, and the nan marker is then tested with math.isnan.
- The
exceptnamesKeyError, which is a different exception. The division raisesZeroDivisionError, so it does not match the except, and the program stops. Change the except toexcept ZeroDivisionError:. The output then isstart,caught,done.
Show the answer
total = 8
count = 0
try:
print("start")
average = total / count
print("average is", average)
except ZeroDivisionError:
print("caught")
print("done")What you now know
- A division or remainder by zero raises
ZeroDivisionErrorin Python for every number type, with the messagedivision by zero. - An uncaught exception stops the program and prints a traceback that shows the file and line.
- Catch the error with
tryandexcept ZeroDivisionError, or check the divisor withifbefore the division. - Python does not return
infornanfrom a division. Create them withfloat("inf")andfloat("nan")when a marker is what the program needs. nanis not equal to itself, so check for it withmath.isnan, not==.- Choose what an empty or zero case returns as part of the function's contract, and say so in the function's name or comment.