set()脱重原理


文書ディレクトリ
  • スタート
  • カスタムデータ構造
  • __eq__関数
  • __hash__関数
  • 重量除去原理
  • スタート
    周知のようにset()はPythonの「天然脱重因子」である.一連のデータ、例えばlyst=[1,1,2,4,4]に対して、私たちはよくsetして、つまり:set(lyst)、重み付けの目的を達成します.
    では、set()はどのようにして重くしますか?
    カスタムデータ構造
    実際の開発ニーズに合わせるためには、データ構造をカスタマイズする必要があります.一般的な例Studentで言えば.
    class Student(object):
        def __init__(self, name, age, sid):
            self.name = name
            self.age = age
            self.sid = sid
    

    次に、stu 1とstu 2の2つのStudioオブジェクトを例に挙げます.名前はname、年齢age、学号sidと同じです.現実の生活では、この二人の学生は同じ人だと考えられる.
    stu1 = Student("zhong", 15, 11198)
    stu2 = Student("zhong", 15, 11198)
    
    print(set([stu1, stu2]))
    #   :{<__main__.student object="" at="">, <__main__.student object="" at="">}
    

    しかしset()はそうは思わないので,デウェイト効果は実現しなかった.
    __eq__関数#カンスウ#
    実際、比較オペレータ==を使用すると、Python解釈器はstu 1がstu 2に等しくないと考えていることがわかります.
    print(stu1 == stu2)  #   :False
    

    プログラムが現実的なニーズに従って実行されていないため、このような現象が発生します.現実的なニーズは、名前、年齢、学号が同じであれば、きっと同じ人なので、魔法の方法__eq__()を書き直す必要があります.コードは次のとおりです.
    class Student(object):
        def __init__(self, name, age, sid):
            self.name = name
            self.age = age
            self.sid = sid
    
        def __eq__(self, other):
            return self.name == other.name and \
                   self.age == other.age and \
                   self.sid == other.sid
    
    stu1 = Student("zhong", 15, 11198)
    stu2 = Student("zhong", 15, 11198)
    print(stu1 == stu2)  #   :True
    

    今、setで重くすることができますか?
    print(set([stu1, stu2]))
    ---------------------------------
    Traceback (most recent call last):
      File "xxxxxxxxx", line 18, in <module>
        print(set([stu1, stu2]))
    TypeError: unhashable type: 'Student'
    

    残念ながら、解釈器が間違っています.Studioタイプのオブジェクトはハッシュできないということです.
    __hash__関数#カンスウ#
    Studioに__eq__()関数を追加していない場合、set()はまだエラーを報告していませんが、今はハッシュできませんか?幸いなことに、__hash__()メソッドを書き換えて、元のデフォルトのハッシュ処理ロジックを変更することができます.
    class Student(object):
        def __init__(self, name, age, sid):
            self.name = name
            self.age = age
            self.sid = sid
    
        def __eq__(self, other):
            return self.name == other.name and \
                   self.age == other.age and \
                   self.sid == other.sid
    
        def __hash__(self):
            return hash((self.name, self.age, self.sid))
    
    stu1 = Student("zhong", 15, 11198)
    stu2 = Student("zhong", 15, 11198)
    print(set([stu1, stu2]))
    #   :{<__main__.student object="" at="">}
    

    便宜上、ここではtupleの可変特性を用いて、ハッシュ処理を正しく通過させることができる.この時私たちはset()で重くして、成功したことを発見しました!
    上記のコードに基づいてeq関数を削除しようとすると、set()が再失効していることがわかります.ハッシュの結果は同じですが.
    class Student(object):
        def __init__(self, name, age, sid):
            self.name = name
            self.age = age
            self.sid = sid
    
        def __hash__(self):
            return hash((self.name, self.age, self.sid))
    
    stu1 = Student("zhong", 15, 11198)
    stu2 = Student("zhong", 15, 11198)
    print(set([stu1, stu2]))  #   :{<__main__.student object="" at="">, <__main__.student object="" at="">}
    print(hash(stu1) == hash(stu2))  #   : True
    

    げんじゅうげんり
    前のステップで導いたように、set()の重み付け原理も得られました.
  • set()関数では、オブジェクトの__hash__()メソッドが先に呼び出され、hash結果が取得されます.
  • hash結果が同じであれば、比較オペレータ==(すなわち呼び出し関数__eq__())で両者の値が等しいか否かを判断する.
  • もしすべて等しいならば、重さを取り除きます;そうでなければset()は両者が異なり,両方とも結果に残ると考えられる.