natknąłem się na ten ciekawy przykład dzisiajJak Python 2.7 porównać przedmioty wewnątrz listy
class TestableEq(object):
def __init__(self):
self.eq_run = False
def __eq__(self, other):
self.eq_run = True
if isinstance(other, TestableEq):
other.eq_run = True
return self is other
>>> eq = TestableEq()
>>> eq.eq_run
False
>>> eq == eq
True
>>> eq.eq_run
True
>>> eq = TestableEq()
>>> eq is eq
True
>>> eq.eq_run
False
>>> [eq] == [eq]
True
>>> eq.eq_run # Should be True, right?
False
>>> (eq,) == (eq,) # Maybe with tuples?
True
>>> eq.eq_run
False
>>> {'eq': eq} == {'eq': eq} # dicts?
True
>>> eq.eq_run
False
>>> import numpy as np # Surely NumPy works as expected
>>> np.array([eq]) == np.array([eq])
True
>>> eq.eq_run
False
Wydaje się więc, że porównania wewnątrz kontenerów działa inaczej w Pythonie. Spodziewam się, że wywołanie ==
będzie korzystać z implementacji każdego obiektu __eq__
, w przeciwnym razie o co chodzi? Dodatkowo
class TestableEq2(object):
def __init__(self):
self.eq_run = False
def __eq__(self, other):
self.eq_run = True
other.eq_run = True
return False
>>> eq = TestableEq2()
>>> [eq] == [eq]
True
>>> eq.eq_run
False
>>> eq == eq
False
>>> eq.eq_run
True
Czy to znaczy, że Python używa is
z poziomu implementacji kontenera z __eq__
zamiast? Czy istnieje sposób obejścia tego?
Moim przypadkiem użycia jest to, że buduję strukturę danych dziedzicząc z niektórych ABC z collections
i chcę napisać testy, aby upewnić się, że moja struktura zachowuje się poprawnie. Pomyślałem, że łatwo byłoby wstrzyknąć wartość, która została zarejestrowana podczas porównywania, ale ku mojemu zdziwieniu test się nie powiódł, gdy sprawdzałem, czy to porównanie miało miejsce.
EDYCJA: Należy wspomnieć, że jest to na Pythonie 2.7, ale widzę to samo zachowanie na 3.3.
Jeśli 'x to y', nie ma powodu, aby wywoływać' x == y'. Wyobrażam sobie, że Python bierze ten skrót. Można to zweryfikować/obalić, tworząc w testach 'eq1' * i * an' eq2', a następnie używając '[eq1] == [eq2]'. – user2864740
@ user2864740 Jeśli chciałbym, aby Python używał 'is', użyłbym go. Nie chcę po prostu porównywać, czy obiekty są takie same, chcę poznać wynik '=='. Jest duża różnica i jestem zaskoczony, że Python wydaje się źle to rozumieć. Naprawdę sprowadza się do operacyjnej różnicy między '[eq] == [eq]' a '[eq1] == [eq2]'. W pierwszym przypadku Python zwróci "True" bez względu na implementację '__eq__', ale w drugim przypadku wywoła' eq1 .__ eq __ (eq2) '. Dlaczego różne wdrożenia? Dlaczego nie pozwolić mi wybrać, w jaki sposób należy porównywać elementy wewnątrz kontenera? – bheklilr
Nie ma znaczenia, co ma robić Python. – user2864740