環境設定 数値 文字列 正規表現 リスト タプル 集合 辞書 ループ 関数 クラス データクラス 時間 パス ファイル スクレイピング その他

Python でクラスのオブジェクトを比較するには __lt__ と __eq__ を定義する - インスタンスに大小関係をつくる方法

Python で独自に定義したクラスのオブジェクトを比較できるか実験します。

class City:
    def __init__(self, name, population, crime):
        self.name = name
        self.population = population
        self.crime = crime


adachi = City(name='足立区', population=690448, crime=3212)
bunkyo = City(name='文京区', population=229828, crime=808)

print(adachi < bunkyo)
# TypeError: '<' not supported between instances of 'City' and 'City'

City インスタンスの比較はサポートされていないと警告がでました。ちなみにインスタンス変数は

population 2022 年 10 月における人口
crime 2021 年の犯罪数

を意味します。数値は

文京区人口統計資料
足立区の年齢別人口
区市町村の町丁別、罪種別及び手口別認知件数

から引用しました。

演算子を定義する

class City:
    def __init__(self, name, population, crime):
        self.name = name
        self.population = population
        self.crime = crime

    def __lt__(self, other):
        rate = self.crime / self.population * 100
        other_rate = other.crime / other.population * 100
        return rate < other_rate


adachi = City(name='足立区', population=690448, crime=3212)
bunkyo = City(name='文京区', population=229828, crime=808)

print(bunkyo < adachi)  # True

クラスに __lt__ を定義すると < が使えるようになります。__lt__ は自分と他人を引数とします。犯罪率で都市の大小関係を示すため、自分の犯罪率 rate と他人の犯罪率 other_rate を計算しました。

この関数は、自分の値が他人のそれより小さいときに True を返し、それ以外で False を返します。

反対の記号も定義される

__lt__< を意味しますが、__lt__ を定義すると > も使えるようになります。

print(adachi > bunkyo)  # True

等号

上のままでは等号が不正確になります。

class City:
    def __init__(self, name, population, crime):
        self.name = name
        self.population = population
        self.crime = crime

    def __lt__(self, other):
        rate = self.crime / self.population * 100
        other_rate = other.crime / other.population * 100
        return rate < other_rate


bunkyo = City(name='文京区', population=229828, crime=808)
sample = City(name='', population=229828, crime=808)

print(bunkyo == sample)  # False

人口と犯罪が同じ bunkyo と sample は犯罪率が等しく、bunkyo == sample は本来 True です。そこで __eq__ を定義します。

class City:
    def __init__(self, name, population, crime):
        self.name = name
        self.population = population
        self.crime = crime

    def __eq__(self, other):
        rate = self.crime / self.population * 100
        other_rate = other.crime / other.population * 100
        return rate == other_rate

    def __lt__(self, other):
        rate = self.crime / self.population * 100
        other_rate = other.crime / other.population * 100
        return rate < other_rate


bunkyo = City(name='文京区', population=229828, crime=808)
sample = City(name='', population=229828, crime=808)

print(bunkyo == sample)  # True

__eq__ はオブジェクトが等しいかどうかをチェックするさいに呼ばれます。こうしてオブジェクトの大小関係がおおむね定義されました。

Python クラス