Embercode
✕
Variables and Data TypesLesson 14 of 16

35 min read

Division by zero in Python

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:

Python · editable

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 zero

Each 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 4 gives the file and the line where the error happened. Line 4 is the line with total / count. The path is shortened here, and your path shows the folder where you saved the file.
  • The line under the File line copies the code, and the ^ and ~ marks show which part of the expression failed.
  • ZeroDivisionError is the name of the exception. The name says the error is about dividing by zero.
  • division by zero is 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:

Python · editable
caught: division by zero
program keeps running

When 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.

Python · editable
2.5
None

The 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:

Python · editable
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 zero

The 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.

Python · editable
inf -inf True
nan
nan
False True
True

The 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:

Python · editable
decimal: DivisionByZero
decimal 0/0: InvalidOperation

The 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.

Python · editable
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: True

The 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.

Python · editable
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:

OptionWhat the user seesWhat can go wrong
Raise the errorThe request fails or the program closesThe error is loud, but it stops work the user wanted
Return 0A number that looks like a real resultA wrong answer looks normal, and nobody notices
Return nanThe text nan on screennan 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.

  1. What does this program print? Explain why.
x = 0.0
print(-3 / x)
  1. Which of these expressions raise ZeroDivisionError when they run: 5 / 0, 5.0 / 0, 0.0 / 0.0, 0 / 0? Explain the rule in one sentence.

  2. Write a function safe_divide(a, b) that returns a / b when b is not zero and returns 0 when b is zero. Then call it with the pairs (10, 0) and (10, 4).

  3. A program sets ratio to x / y when y is not 0.0, and to float("nan") when y is 0.0. Write a check that prints no ratio when ratio is nan, and prints the value when it is a number. Use math.isnan, not ==.

  4. 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.

  1. The program raises ZeroDivisionError on the second line. The divisor is a float, but Python does not return -inf for a float division by zero.

Show the answer

Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero

To get negative infinity on purpose, write float("-inf") in the code.

  1. 5 / 0 and 0 / 0 raise, and so do 5.0 / 0 and 0.0 / 0.0. The rule is that every division with a zero divisor raises in Python, whatever the number types are.

  2. 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.

  1. Use math.isnan on 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.

  1. The except names KeyError, which is a different exception. The division raises ZeroDivisionError, so it does not match the except, and the program stops. Change the except to except ZeroDivisionError:. The output then is start, 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 ZeroDivisionError in Python for every number type, with the message division by zero.
  • An uncaught exception stops the program and prints a traceback that shows the file and line.
  • Catch the error with try and except ZeroDivisionError, or check the divisor with if before the division.
  • Python does not return inf or nan from a division. Create them with float("inf") and float("nan") when a marker is what the program needs.
  • nan is not equal to itself, so check for it with math.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.
Check yourself: Floats and division by zero (8 questions) →Practice this topic: coding problems for Variables and Data Types →

Stuck? Ask the tutor

Ask about anything in this lesson. Answers are short and use simple words.

Sign in to ask the tutor.

← Booleans and the = trap in Python