Python WebAcademy

Python WebAcademy Blog

PythonのZeroDivisionErrorとは?division by zeroの原因と直し方、空のリストで平均を出すと落ちる理由を初心者向けに解説

|

PythonのZeroDivisionErrorは、0で割り算をしようとしたときに出るエラーです。この記事では、division by zeroなどメッセージの読み方、空のリストで平均を求めたときやユーザー入力で起こる典型的な原因、if文とtry-exceptによる防ぎ方、decimalやstatisticsでの扱いの違いまで、サンプルコードで初心者向けにやさしく解説します。

平均点を計算するだけの簡単なプログラムなのに、ZeroDivisionError: division by zero と表示されて止まってしまった。Pythonを学び始めると、一度はこんな場面に出会うのではないでしょうか。

自分では0で割った覚えなんてないのに、と首をかしげた方も多いはずです。実はこのエラーは、コードを書いた時点ではなく、データの中身によって起こることがほとんどです。

この記事では、ZeroDivisionErrorの意味とメッセージの読み方から、よくある原因、そして落ちないコードの書き方までを順番に解説します。エラーの正体がわかれば、怖がる必要はまったくありません。

サンプルの実行結果は、手元のLinux環境のPython 3.11から3.13で確認したものです。WindowsやmacOSでも、エラーの名前と考え方は同じです。

ZeroDivisionErrorとはどんなエラーなのか

まずは、このエラーが何を知らせているのかを押さえておきましょう。ひとことで言うと、割り算や余りの計算で、割る数が0だったときに出るエラーです。

算数でも、0で割ることはできないと習いましたよね。10個のりんごを0人で分けると1人何個になるか、という問いには答えがありません。

Pythonも同じ考え方をします。答えが決められない計算を無理に進めるのではなく、例外を出してその場で止まるのです。

ZeroDivisionErrorは、ArithmeticErrorという例外の仲間です。ArithmeticErrorは、計算そのものがうまくいかなかったときに使われる例外のグループです。

実際にクラスの関係を確かめると、次のようになっています。

print(ZeroDivisionError.__mro__)
# (<class 'ZeroDivisionError'>, <class 'ArithmeticError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)

except ArithmeticError と書けば、ZeroDivisionErrorも受け止められます。とはいえ範囲が広くなるので、ふだんはZeroDivisionErrorと具体的に書くほうが意図が伝わりやすいです。

エラーメッセージの読み方

次に、メッセージの中身を見てみましょう。実はZeroDivisionErrorは、どの演算子で割ったかによって、少しずつ違うメッセージを出します。

手元で試した結果を、次の表にまとめました。

書いたコード 表示されたメッセージ
1 / 0 division by zero
1 // 0 integer division or modulo by zero
1 % 0 integer modulo by zero
1.0 / 0 float division by zero
1.0 // 0 float floor division by zero
divmod(1, 0) integer division or modulo by zero
0 ** -1 0.0 cannot be raised to a negative power

メッセージにintegerとあれば整数どうしの計算、floatとあれば小数を含む計算で起きたことがわかります。どの行で起きたのかと合わせて読むと、原因の変数を絞り込みやすくなります。

最後の0 ** -1も見落とせません。マイナス乗は1を割る計算と同じなので、0のマイナス乗も同じエラーになります。

なお、メッセージの細かい文言はバージョンによって変わることがあります。たとえば1.0 % 0は、3.12まではfloat moduloでしたが、3.13ではfloat modulo by zeroと表示されました。

エラーが起きた行を探すときは、メッセージより上に表示されるtracebackを読みます。読み方に自信がない方は、こちらの記事が参考になります。 【関連記事】Pythonのエラー文はどこを読めばいい?初心者向けtracebackの見方

ZeroDivisionErrorのよくある原因

ここからが本題です。わざわざ1 / 0と書く人はいませんから、実際のエラーはもっと気づきにくい形でやってきます。

空のリストで平均を求めた

いちばん多いのが、このパターンです。合計をlen()で割って平均を出すコードは、リストが空だと割る数が0になります。

scores = []
average = sum(scores) / len(scores)
# ZeroDivisionError: division by zero

テストでは必ずデータがあったのに、本番では検索結果が0件だった。そんな理由で、ある日突然エラーが出るのです。

私は10年ほどエンジニアとして開発に関わってきましたが、月次レポートのバッチがこのエラーで止まった経験があります。新しく追加した店舗の売上データがまだ1件もなく、件数0で割っていたのが原因でした。

ユーザーの入力や外部のデータが0だった

人数や個数をinput()で受け取って割り算に使う場合も要注意です。利用者が0を入力する可能性は、いつでもあります。

CSVやAPIから受け取った値も同じです。データが欠けていて0として扱われていた、ということは実務でもよくあります。

計算の途中で0になった

割る数が、別の計算の結果になっていることもあります。たとえば、a - b のように引き算した結果で割ると、aとbが同じ値のときに0になります。

このタイプはコードを読むだけでは気づきにくいのが難点です。エラーが出たら、割る数にあたる変数を一度printして、どんな値になっているか確かめてみてください。

0で割らないための防ぎ方

原因がわかったところで、対策を見ていきましょう。方法は大きく分けて、先に確かめる方法と、起きてから受け止める方法の2つがあります。

先にif文で確かめる

もっともシンプルなのは、割る前に0でないかを確かめることです。次の関数は、空のリストが渡されたら平均の代わりにNoneを返します。

def safe_average(values):
    if not values:
        return None
    return sum(values) / len(values)


print(safe_average([80, 90, 70]))  # 80.0
print(safe_average([]))            # None

if not values は、リストが空かどうかを調べる書き方です。空のリストは偽として扱われるので、これだけで判定できます。

0の代わりに何を返すかは、場面によって変わります。平均点ならNone、達成率なら0として表示する、というように0件のときに何を見せたいかを先に決めておくことが大切です。

try-exceptで受け止める

もうひとつは、まず計算してみて、ZeroDivisionErrorが起きたら対処する書き方です。割る数がどこで0になるか予想しにくいときに便利です。

def calc_rate(done, total):
    try:
        return done / total * 100
    except ZeroDivisionError:
        print(f"totalが0のため達成率を計算できません(done={done})")
        return 0.0


print(calc_rate(3, 4))  # 75.0
print(calc_rate(0, 0))  # メッセージを表示して 0.0

ここで大事なのは、エラーをただ隠すのではなく、どの値で失敗したかを残しておくことです。except ZeroDivisionError: pass のように黙って握りつぶすと、あとで原因を探すのに苦労します。

どちらの方法を選ぶかは、好みよりも状況で決めるのがおすすめです。違いを表にまとめておきます。

方法 向いている場面 注意点
if文で先に確かめる 0になる条件がはっきりしている 割る数が複数あると条件が増える
try-exceptで受け止める 0になる場所を予想しにくい 握りつぶさず、値を記録する

try-exceptの基本や、else・finallyの使い方をおさらいしたい方は、こちらの記事でくわしく解説しています。 【関連記事】Pythonのtry・except・else・finallyとは?例外処理の基本の流れ

floatの小ささと割り算の落とし穴

ZeroDivisionErrorを防ぐために、割る数が0かどうかを == 0 で比べることがあります。整数なら問題ありませんが、小数の計算では少し注意が必要です。

たとえば 0.1 + 0.2 - 0.3 は、数学的には0になるはずです。ところがPythonで計算すると、ごくわずかな誤差が残って0にはなりません。

x = 0.1 + 0.2 - 0.3
print(x == 0)   # False
print(1 / x)    # 1.8014398509481984e+16

0ではないのでエラーにはならず、とてつもなく大きな数が返ってきました。エラーが出ないぶん、気づかないまま間違った結果を使ってしまう危険があります。

小数の比較では、math.isclose()で十分に近いかどうかを判定する方法が使えます。誤差が生まれる仕組みが気になる方は、こちらの記事もあわせて読んでみてください。 【関連記事】Pythonの丸め誤差とは?初心者にもわかる原因と対策

decimalやstatisticsではどうなるのか

標準ライブラリの中には、0での割り算を独自に扱うものもあります。代表的な2つを見ておきましょう。

ひとつ目は、お金の計算などで使われるdecimalモジュールです。Decimal(1) / 0 を計算すると、decimal.DivisionByZeroという例外が出ます。

このDivisionByZeroは、ZeroDivisionErrorを継承しています。そのため、except ZeroDivisionError と書いておけば、ふつうの割り算と同じように受け止められます。

ただし、Decimal(0) / 0 のように0を0で割ると、手元ではdecimal.InvalidOperationという別の例外になりました。こちらはZeroDivisionErrorの仲間ではないので、except ZeroDivisionErrorでは捕まえられません。

二つ目は、平均や中央値を求めるstatisticsモジュールです。statistics.mean([]) のように空のデータを渡すと、ZeroDivisionErrorではなくStatisticsErrorが出ます。

メッセージは mean requires at least one data point で、平均には最低1つのデータが必要だと教えてくれます。0で割ったという結果ではなく、データが空だという原因を直接伝えてくれるので、自分でsum() / len()を書くより親切です。

それぞれの違いを、次の表に整理しました。

計算 出る例外 except ZeroDivisionErrorで捕まるか
1 / 0 ZeroDivisionError 捕まる
Decimal(1) / 0 decimal.DivisionByZero 捕まる
Decimal(0) / 0 decimal.InvalidOperation 捕まらない
statistics.mean([]) statistics.StatisticsError 捕まらない

ライブラリを使うと、同じ0で割る場面でもエラーの種類が変わることがあります。ドキュメントで、どんな例外が出るかを確かめておくと安心です。

statisticsモジュールの使い方は、こちらの記事でくわしく紹介しています。 【関連記事】Pythonのstatisticsとは?平均値にだまされないための基本の統計を初心者向けに解説

ZeroDivisionErrorに強いコードを書くコツ

最後に、実務でも役立つ考え方を紹介します。大切なのは、エラーを消すことよりも、0件という状態をきちんと設計することです。

画面に平均を表示するなら、0件のときは平均をハイフンで表示する。集計のバッチなら、0件の店舗はスキップしてログに残す。このように、0のときの振る舞いを仕様として決めておくと迷いません。

先ほど紹介した月次レポートの失敗のあと、私のチームでは割り算を書くたびに、割る数が0になるのはどんなときかを話し合うようにしました。地味な習慣ですが、それ以来同じ原因で止まったことはありません。

/や//、%の違いをもう一度整理したい方は、こちらの記事が参考になります。 【関連記事】Pythonの割り算とは?/・//・%・divmod()の違いを初心者向けに解説

まとめ

ZeroDivisionErrorは、割り算や余りの計算で割る数が0だったときに出るエラーです。メッセージのintegerやfloatという言葉から、どんな値どうしで計算したのかを読み取れます。

原因の多くは、空のリストで平均を出したり、入力や外部のデータが0だったりする場面です。割る数がいつ0になるのかを考えることが、いちばんの予防になります。

防ぎ方は、if文で先に確かめる方法と、try-exceptで受け止める方法の2つです。どちらを使う場合も、0のときに何を返すかを決め、失敗した値を記録しておきましょう。

decimalやstatisticsのように、独自の例外を出すライブラリもあります。エラーの名前をよく読む習慣をつければ、次に同じ場面に出会っても落ち着いて対処できるはずです。

ここまでお読みいただきありがとうございました。

参考情報

次のアクション

記事で学んだ内容を実際に動かしてみよう

Python WebAcademyでは、ブラウザ上でコードを書きながら基礎から実践まで体系的に学べます。

Python WebAcademyの学習画面

あわせて読む

関連記事

ブログ一覧へ

Python学習ロードマップ

まずはこの3講座から

記事で気になったテーマを、順番に手を動かしながら学べます。

ロードマップを見る