4.

Python 比較演算子|連鎖比較・== と is の違い・float の比較方法

編集
この記事の要点
  • 比較演算子は == != < <= > >= の 6 つ。結果は必ず bool
  • 連鎖比較が書ける: 0 <= x < 10(0 <= x) and (x < 10)
  • ==is同一オブジェクトNone の判定は必ず is None
  • float の == は誤差で外れる。math.isclose() を使う
  • リストやタプルの比較は先頭から順に比べる辞書順。型が違うと TypeError

一覧

演算子意味結果
==等しい1 == 1.0True
!=等しくない"a" != "b"True
< <=より小さい / 以下3 <= 3True
> >=より大きい / 以上3 > 5False

Python には <>(不等号の古い書き方)はありません。!= を使います。

連鎖比較

x = 5
print(0 <= x < 10)          # True   範囲チェックがそのまま書ける
print(1 < 2 < 3 < 4)       # True

# 中央の式は 1 回しか評価されない
def f():
    print("called")
    return 5
print(0 < f() < 10)         # called が 1 回だけ出る

# a == b == c は「3 つとも等しい」
print(1 == 1 == 1)          # True
print(1 == 1 == 2)          # False

==is の使い分け

a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)     # True    中身が同じ
print(a is b)     # False   別オブジェクト

x = None
print(x is None)      # 正しい書き方
print(x is not None)  # 否定は is not(not x is None ではない)

# 小さい int や短い文字列はキャッシュされていて紛らわしい
print(256 is 256)     # True になることがある(実装依存)
print(1000 is 1000)   # False になることがある
# → 値の比較に is を使わない

is を使ってよいのは None / True / False のような唯一のオブジェクトが決まっているものとの比較だけです。

float の比較

print(0.1 + 0.2 == 0.3)        # False   誤差で一致しない

import math
print(math.isclose(0.1 + 0.2, 0.3))                      # True
print(math.isclose(1000.0, 1000.1, rel_tol=1e-3))        # True  相対誤差
print(math.isclose(0.0, 1e-12, abs_tol=1e-9))            # True  絶対誤差

# nan は自分自身とも等しくない
nan = float("nan")
print(nan == nan)         # False
print(math.isnan(nan))    # True   ← 判定はこちら

rel_tol は既定で 1e-09 です。0 との比較だけは相対誤差が効かないので abs_tol を明示してください。

シーケンス・辞書・集合の比較

print([1, 2, 3] == [1, 2, 3])      # True   要素と順序が一致
print([1, 2] < [1, 3])             # True   先頭から辞書順に比較
print([1, 2] < [1, 2, 0])          # True   前半が同じなら短い方が小さい

print((1, 2) == [1, 2])            # False  型が違えば等しくない

print({"a": 1} == {"a": 1})        # True   辞書は順序を問わない
# 辞書に < > は無い(TypeError)

print({1, 2} < {1, 2, 3})          # True   集合の < は「真部分集合」
print({1, 2}.issubset({1, 2}))     # True

異なる型どうしの比較

print(1 == 1.0)      # True    数値どうしは型が違っても比べられる
print(1 == "1")      # False   文字列とは等しくならない(例外にもならない)

# 大小比較は例外になる
# print(1 < "1")
# TypeError: '<' not supported between instances of 'int' and 'str'

# bool は int のサブクラス
print(True == 1, False == 0)   # True True
print(True + True)             # 2

Python 2 では型が違っても大小比較できましたが、Python 3 では TypeError になります。ソート時に None が混ざって落ちるのは、この仕様が原因であることが多いです。

自作クラスの比較

from functools import total_ordering

@total_ordering
class Ver:
    def __init__(self, major, minor):
        self.major, self.minor = major, minor
    def __eq__(self, other):
        return (self.major, self.minor) == (other.major, other.minor)
    def __lt__(self, other):
        return (self.major, self.minor) < (other.major, other.minor)

print(Ver(1, 2) < Ver(1, 10))   # True
print(Ver(1, 2) >= Ver(1, 2))   # True   total_ordering が残りを補う

__eq__ を定義したクラスは既定でハッシュ不可になり set や辞書のキーに使えません。必要なら __hash__ も定義してください。

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 算術演算子
  2. 文字列演算子
  3. 代入演算子
  4. 比較演算子
  5. 論理演算子
  6. ビット演算子

最近更新/作成されたページ