Warum ruft a == b auf b .__ EQ__, wenn er von der Liste abgeleitet ist und mit fehlender Überschrift ein Tupel abgeleite
Posted: 25 Apr 2025, 10:13
Hintergrund
Ich schreibe Mathematik -Dienstprogrammklassen ListVector und tupleVector ,
Erben aus der Liste bzw. Tuple :
Ich muss daher die __eq __ und __ne __ in meinen beiden Vektorklassen überschreiben. Klasse,
Aber ich habe zunächst vergessen, sie in meinem ListVector < /code> Klasse zu implementieren.
Erwartete Verhalten: Da ich vergessen habe, __eq __ und __ne __ In ListVector zu überschreiben, erwarte ich, dass der Aufruf von == Call zum Auflisten fällt .__ EQ __ , was false ,
und so dass der Assprüger fehlschlägt. Verhalten: Aufrufe reflektierter TupleVector .__ EQ __ Stattdessen,
, was true zurückgibt, und so ist die Behauptung erfolgreich! LIST .__ EQ __ < /code>? < /p>
Nach den hier beschriebenen Regeln
(was aus dieser FAQ entnommen wird),
Ich denke, es sollte die Liste nennen .__ EQ __ < /code>. überschrieben __eq __ (dh type (a) .__ EQ __ ist kein Objekt .__ EQ __ ), dann ist das Ergebnis a .__ EQ __ (b) . /> < /blockquote>
Mein Lesen der Dokumentation scheint auch zu der gleichen Schlussfolgerung zu führen wie die FAQ (dh die Methode des linken Operanden, d. H. List .__ Gl. __ < /code>, sollte aufgerufen werden): < /p>
Wenn der Operand den Operand der Operand der Operands von der richtigen Art und Oper von unterschiedlichem Operand ist, ist der Typ. Typ, die reflektierte Methode des rechten Operand "sollte fehlschlagen.
Ich schreibe Mathematik -Dienstprogrammklassen ListVector und tupleVector ,
Erben aus der Liste bzw. Tuple :
Code: Select all
class ListVector(list):
...
class TupleVector(tuple):
...
< /code>
(Abgesehen davon: Ich behaupte nicht unbedingt, dass dies wirklich eine gute Idee ist; in der Tat,
bin ich mir bewusst, dass ich dies wohl nicht tun sollte, da meine beabsichtigten Beziehungen logisch "has-a"-"-"-"-als" is-a ",
und unangemessenes Basspflichten, das von dem Basis-AS-AS-AS-AS-AS-AS-AS-AS-AS-AS-AS-AS-AS-ASS-ASS-ASS-ASS-ASS-ASS-ASS-ASS-ASS-ASS-ASS, ist, wenn es nicht gefährlich ist, wenn es nicht gefährlich ist. Meine
Klassen, z. /> [url=viewtopic.php?t=14917]Ich möchte[/url] den Vergleich von ListVector < /code> gegen TupleVector < /code> verwenden. Ich möchte, dass dies erfolgreich ist: < /p>
assert ListVector((1,2,3)) == TupleVector((1,2,3))
< /code>
Beachten Sie, dass sich dies vom Verhalten der Basisklasse unterscheidet: < /p>
assert list((1,2,3)) != tuple((1,2,3))
< /code>
i.e.
assert [1,2,3] != (1,2,3)
Aber ich habe zunächst vergessen, sie in meinem ListVector < /code> Klasse zu implementieren.
Code: Select all
assert ListVector((1,2,3)) == TupleVector((1,2,3)) # unexpectedly succeeds!
und so dass der Assprüger fehlschlägt. Verhalten: Aufrufe reflektierter TupleVector .__ EQ __ Stattdessen,
, was true zurückgibt, und so ist die Behauptung erfolgreich! LIST .__ EQ __ < /code>? < /p>
Nach den hier beschriebenen Regeln
(was aus dieser FAQ entnommen wird),
Ich denke, es sollte die Liste nennen .__ EQ __ < /code>. überschrieben __eq __ (dh type (a) .__ EQ __ ist kein Objekt .__ EQ __ ), dann ist das Ergebnis a .__ EQ __ (b) . /> < /blockquote>
Mein Lesen der Dokumentation scheint auch zu der gleichen Schlussfolgerung zu führen wie die FAQ (dh die Methode des linken Operanden, d. H. List .__ Gl. __ < /code>, sollte aufgerufen werden): < /p>
Wenn der Operand den Operand der Operand der Operands von der richtigen Art und Oper von unterschiedlichem Operand ist, ist der Typ. Typ, die reflektierte Methode des rechten Operand
Code: Select all
#!/usr/bin/python3
class ListVector(list):
# OOPS! Forgot to implement __eq__ and __ne__ for ListVector
# ...
pass
class TupleVector(tuple):
def __eq__(self, other):
print("TupleVector.__eq__ called")
# strict=True so comparing Vectors of unequal length will throw
return all(x==y for x,y in zip(self,other, strict=True))
def __ne__(self, other):
return not self.__eq__(other)
# ...
# Unit test
assert repr(ListVector((1,2,3))) == "[1, 2, 3]" # succeeds as expected
assert repr(TupleVector((1,2,3))) == "(1, 2, 3)" # succeeds as expected
assert TupleVector((1,2,3)) == ListVector((1,2,3)) # emits "TupleVector.__eq__ called" and succeeds, as expected
assert ListVector((1,2,3)) == TupleVector((1,2,3)) # WTF: unexpectedly emits "TupleVector.__eq__ called" and succeeds!
# Confirm that the condition "type(a).__eq__ isn’t object.__eq__", mentioned
# in the decision procedure in the FAQ, holds:
assert ListVector.__eq__ is list.__eq__ # because I forgot to override that
assert ListVector.__eq__ is not object.__eq__ # because list.__eq__ is not object.__eq__
assert TupleVector.__eq__ is not tuple.__eq__ # because I remembered that override
assert TupleVector.__eq__ is not object.__eq__ # definitely not
< /code>
Die (überraschende) Ausgabe ist: < /p>
TupleVector.__eq__ called
TupleVector.__eq__ called
< /code>
Ich habe das stattdessen erwartet, "TupleVector.__eq__ called< /code> "sollte
nur einmal statt zweimal emittiert werden,
und der"assert ListVector((1,2,3)) == TupleVector((1,2,3))