Powinieneś zaimplementować metodę __eq__
:
class MyClass:
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def __eq__(self, other):
if not isinstance(other, MyClass):
# don't attempt to compare against unrelated types
return NotImplemented
return self.foo == other.foo and self.bar == other.bar
Teraz wyświetla:
>>> x == y
True
Zauważ, że implementacja __eq__
automatycznie sprawi, że instancje twojej klasy nie będą dostępne, co oznacza, że nie mogą być przechowywane w zestawach i nagraniach. Jeśli nie modelujesz niezmiennego typu (tj. Jeśli atrybuty foo
i bar
mogą zmienić wartość w trakcie życia obiektu), zalecamy pozostawienie instancji jako nie do powstrzymania.
Jeśli modelujesz niezmienny typ, powinieneś również zaimplementować hook modelu danych __hash__
:
class MyClass:
...
def __hash__(self):
# necessary for instances to behave sanely in dicts and sets.
return hash((self.foo, self.bar))
Ogólne rozwiązanie, takie jak pomysł zapętlania __dict__
i porównywania wartości, nie jest wskazane - nigdy nie może być naprawdę ogólne, ponieważ __dict__
mogą zawierać nieporównywalne lub niemożliwe do skasowania typy.
Uwaga: pamiętaj, że przed Python 3 może być konieczne użycie __cmp__
zamiast __eq__
. Użytkownicy Pythona 2 mogą również chcieć zaimplementować __ne__
, ponieważ rozsądne zachowanie domyślne nierówności (tj. Odwrócenie wyniku równości) nie zostanie automatycznie utworzone w Pythonie 2.
return NotImplemented
(zamiast podbijaniaNotImplementedError
). Temat ten jest omawiany tutaj: stackoverflow.com/questions/878943/…Zastępujesz operatory porównania bogatego w swoim obiekcie.
Lubię to:
źródło
__eq__()
, ale tylko jeden__lt__()
,__le__()
,__gt__()
czy__ge__()
potrzebna jest oprócz tego. Na tej podstawie Python może wywnioskować inne metody. Zobaczfunctools
po więcej informacji.functools
modułu, ale nie działa w przypadku standardowych komparatorów:MyObj1 != Myobj2
działa tylko, jeśli__ne__()
metoda jest zaimplementowana.@functools.total_ordering
dekoratora w swojej klasie, a następnie, jak wyżej, możesz zdefiniować tylko__eq__
jedno i drugie, a reszta zostanie wyprowadzonaZaimplementuj
__eq__
metodę w swojej klasie; coś takiego:Edycja: jeśli chcesz, aby Twoje obiekty były równe wtedy i tylko wtedy, gdy mają słowniki równych wystąpień:
źródło
self is other
sprawdzić, czy są one tym samym przedmiotem.AttributeError
. Musisz wstawić linięif hasattr(other, "path") and hasattr(other, "title"):
(jak ten ładny przykład w dokumentacji Pythona).Podsumowując:
__eq__
raczej implementację niż__cmp__
, chyba że uruchomisz Python <= 2.0 (__eq__
został dodany w 2.1)__ne__
(powinno to być coś wyjątkowegoreturn not self.__eq__(other)
lubreturn not self == other
wyjątek)Jeśli chcesz porównać z obiektem, który może być Brak, musisz go zaimplementować. Tłumacz nie może zgadnąć ... (patrz przykład poniżej)
źródło
W zależności od konkretnego przypadku możesz:
Zobacz słownik Pythona z pól obiektu
źródło
W przypadku Dataclasses w Pythonie 3.7 (i nowszych) porównanie instancji obiektów dla równości jest wbudowaną funkcją.
Backportu do Dataclasses dostępne Pythona 3.6.
źródło
Podczas porównywania instancji obiektów
__cmp__
wywoływana jest funkcja.Jeśli operator == nie działa dla Ciebie domyślnie, zawsze możesz ponownie zdefiniować
__cmp__
funkcję dla obiektu.Edytować:
Jak już wspomniano,
__cmp__
funkcja jest przestarzała od 3.0. Zamiast tego powinieneś użyć metod „bogatego porównania” .źródło
Jeśli masz do czynienia z jedną lub kilkoma klasami, których nie możesz zmienić od wewnątrz, istnieją ogólne i proste sposoby, aby to zrobić, które również nie zależą od biblioteki specyficznej dla różnic:
Najłatwiejsza, najbardziej niebezpieczna metoda dla bardzo złożonych obiektów
pickle
jest bardzo popularną biblioteką serializacji dla obiektów Pythona i dlatego będzie w stanie serializować praktycznie wszystko. W powyższym fragmencie porównuję numerstr
seryjnya
z kodem zb
. W przeciwieństwie do kolejnej metody, ta ma tę zaletę, że sprawdza także niestandardowe klasy.Największy problem: ze względu na specyficzne metody porządkowania i kodowania [de / en]
pickle
mogą nie dawać tego samego wyniku dla równych obiektów , szczególnie w przypadku bardziej złożonych (np. List zagnieżdżonych instancji klasy niestandardowej), jak to często można znaleźć w niektórych bibliotekach stron trzecich. W takich przypadkach zaleciłbym inne podejście:Dokładna, bezpieczna dla dowolnego obiektu metoda
Możesz napisać rekurencyjną refleksję, która da ci obiekty do serializacji, a następnie porównać wyniki
Teraz nie ma znaczenia, jakie są twoje obiekty, zapewniona jest głęboka równość
Liczba porównywalnych elementów również nie ma znaczenia
Moim przypadkiem użycia było sprawdzenie głębokiej równości między różnorodnym zestawem już przeszkolonych modeli uczenia maszynowego w testach BDD. Modele należały do różnorodnego zestawu bibliotek stron trzecich. Z pewnością zastosowanie
__eq__
innych odpowiedzi tutaj sugeruje, że nie było dla mnie opcją.Obejmuje wszystkie bazy
Możesz znajdować się w scenariuszu, w którym co najmniej jedna z porównywanych klas niestandardowych nie ma
__dict__
implementacji . To nie jest powszechne w jakikolwiek sposób, ale jest to przypadek podtypu w sklearn Losowa Lasu klasyfikatora:<type 'sklearn.tree._tree.Tree'>
. Traktować te sytuacje, w każdym indywidualnym przypadku - np konkretnie , postanowiłem zastąpić zawartość strapionych typu z treścią metody, która daje mi informacje na reprezentatywnej instancji (w tym przypadku__getstate__
metoda). W tym celubase_typed
stał się drugi do ostatniego rzęduEdit: dla dobra organizacji, wymieniłem dwa ostatnie wiersze
base_typed
zreturn dict_from(obj)
, i wdrożył naprawdę rodzajowy refleksji aby pomieścić więcej niejasnych bibliotekami (Patrzę na ciebie, Doc2Vec)Nieważne, że żadna z powyższych metod nie daje wyników
True
dla różnych obiektów o tych samych parach klucz-wartość, ale o różnych porządkach klucz / wartość, jak wAle jeśli chcesz, możesz wcześniej skorzystać z wbudowanej
sorted
metody Pythona .źródło
Napisałem to i umieściłem w
test/utils
module w moim projekcie. W przypadkach, gdy nie jest to klasa, wystarczy po prostu zaplanować, przejdzie to przez oba obiekty i zapewniJest duży ... nie jest seksowny ... ale och boi to działa!
Możesz to trochę posprzątać, usuwając
_assert
i używając zwykłego ol ',assert
ale wtedy wiadomość, którą otrzymasz, gdy zawiedzie, jest bardzo nieprzydatna.źródło
Powinieneś zaimplementować metodę
__eq__
:źródło
Poniżej działa (w moich ograniczonych testach), dokonując głębokiego porównania między dwiema hierarchiami obiektów. Obsługuje różne przypadki, w tym przypadki, gdy same obiekty lub ich atrybuty są słownikami.
Jest to bardzo trudny kod, więc w komentarzach dodaj wszelkie przypadki, które mogą nie działać.
źródło
źródło
Jeśli chcesz uzyskać porównanie atrybut po atrybucie i sprawdzić, czy i gdzie się nie powiedzie, możesz skorzystać z następującego opisu listy:
Dodatkową zaletą jest to, że możesz wycisnąć go z jednej linii i wejść w okno „Oceń wyrażenie” podczas debugowania w PyCharm.
źródło
Próbowałem początkowego przykładu (patrz 7 powyżej) i nie działał w ipython. Zauważ, że cmp (obj1, obj2) zwraca „1”, gdy jest implementowany przy użyciu dwóch identycznych instancji obiektów. Co dziwne, kiedy modyfikuję jedną z wartości atrybutów i dokonuję ponownej porównania, używając cmp (obj1, obj2) obiekt nadal zwraca „1”. (westchnienie...)
Ok, więc musisz powtórzyć dwa obiekty i porównać każdy atrybut za pomocą znaku ==.
źródło
Wystąpienie klasy w porównaniu z == nie jest równe. Najlepszym sposobem jest przypisanie funkcji cmp do klasy, która wykona te czynności.
Jeśli chcesz dokonać porównania według zawartości, możesz po prostu użyć cmp (obj1, obj2)
W twoim przypadku cmp (doc1, doc2) Zwróci -1, jeśli zawartość jest taka sama.
źródło