Beide coördinaten vergelijken
Vul Point.__eq__(other) aan: twee objecten van hetzelfde concrete type zijn gelijk wanneer x én y gelijk zijn. Geef daarvoor echte booleans terug; gelijkheid hangt niet af van dezelfde identiteit.
Twee opgeslagen coördinaten kunnen allebei het punt (2, 5) voorstellen. Het zijn toch twee afzonderlijke objecten. Soms wil je hun plaats vergelijken, en soms wil je juist weten of twee variabelen naar precies hetzelfde object verwijzen.
Identiteit gaat over hetzelfde object en wordt met is onderzocht. Waardegelijkheid gaat over de betekenis van de opgeslagen gegevens en wordt gewoonlijk met == gevraagd. Die twee vragen kunnen bij twee gelijke punten verschillende antwoorden geven.
Een dataclass krijgt standaard een vergelijking van haar velden. In het voorbeeld staan twee afzonderlijke instanties met dezelfde gegevens. Voorspel zowel de gelijkheidsvergelijking als de identiteitscontrole.
from dataclasses import dataclass
@dataclass
class Coordinate:
row: int
column: int
first = Coordinate(2, 5)
second = Coordinate(2, 5)
print(first == second)
print(first is second)
alias = first
print(alias is first)True False True
Een variabele extra aan hetzelfde object koppelen verandert zijn identiteit niet. Een nieuw object met dezelfde veldwaarden blijft wel een afzonderlijke instantie. Het verschil wordt belangrijk zodra een van die objecten later kan veranderen.
Bij een gewone klasse kun je __eq__ schrijven om de gelijkheidsvergelijking vorm te geven. De methode ontvangt self en other. Voor twee passende punten vergelijk je zowel de x- als de y-waarde.
Als je alleen de eerste coördinaat vergelijkt, worden bijvoorbeeld (2, 5) en (2, 9) ten onrechte gelijk. Als je alleen self is other teruggeeft, blijven twee afzonderlijke punten met dezelfde coördinaten ongelijk. Kies dus de velden die samen de betekenis van de waarde bepalen.
Voor een vergelijking die jouw methode niet ondersteunt, is er de speciale waarde NotImplemented. Geef die terug wanneer het andere object volgens jouw contract niet bij deze vergelijking hoort. Je werpt hiervoor geen NotImplementedError en maakt er geen tekst van.
Met deze waarde laat je Python ruimte om de andere kant van de vergelijking te proberen. Wanneer beide kanten een gelijkheidsvergelijking niet ondersteunen, kan Python voor == terugvallen op identiteit. NotImplemented is daarom een antwoord binnen het vergelijkingsprotocol, geen gewoon False voor ieder onbekend object.
class Coordinate:
def __init__(self, row, column):
self.row = row
self.column = column
def __eq__(self, other):
if type(other) is not type(self):
return NotImplemented
return self.row == other.row and self.column == other.column
first = Coordinate(2, 5)
print(first == Coordinate(2, 5))
print(first == Coordinate(2, 9))
print(first.__eq__((2, 5)) is NotImplemented)
print(first == (2, 5))True False True False
In deze les vergelijken we puntwaarden van hetzelfde concrete type. Een tuple met dezelfde twee getallen is daarmee niet automatisch een Point. Dat voorkomt dat een toevallig vergelijkbare gegevensvorm stilzwijgend dezelfde domeinbetekenis krijgt.
Zonder typecontrole meteen other.x lezen kan bij een ander soort object een AttributeError veroorzaken. De vraag of twee waarden gelijk zijn hoort dan onbedoeld op een foutpad te eindigen. Bepaal eerst of jouw vergelijking dit andere type ondersteunt.
Bij passende objecten vergelijk je de echte waarden. Bij een ander type geef je de afgesproken speciale waarde terug. De controles onderzoeken ook die directe uitkomst, zodat een ongeschikte vergelijking niet alleen door toevallige voorbeeldgegevens verborgen blijft.
Een lijst kan met in zoeken naar een gelijk element. Na een passende __eq__ hoeft het gezochte punt daarom niet dezelfde instantie te zijn als het punt in de lijst. De domeinbetekenis zit in de waarden die jouw klasse vergelijkt.
Een kopie met dezelfde coördinaten kan eveneens gelijk zijn en toch een eigen identiteit hebben. Zo kan een functie een zelfstandige puntwaarde teruggeven zonder de verwijzing van de aanroeper opnieuw te gebruiken. De nieuwe en de oude instantie mogen elkaar daarna niet ongemerkt veranderen.
Vul Point.__eq__(other) aan: twee objecten van hetzelfde concrete type zijn gelijk wanneer x én y gelijk zijn. Geef daarvoor echte booleans terug; gelijkheid hangt niet af van dezelfde identiteit.
Laat Point.__eq__ bij een ander concreet type NotImplemented teruggeven. Dat geldt ook voor een verdere subklasse. De gewone == met een tuple of None moet daarmee False worden, zonder exception.
Maak contains_point(points, target) die een echte boolean geeft voor de aanwezigheid van een gelijk punt. Een afzonderlijke instantie met dezelfde coördinaten moet gevonden worden; verander de lijst niet.
Maak copy_point(point) die een nieuwe Point met dezelfde x en y teruggeeft. De kopie is gelijk maar niet hetzelfde object; een latere wijziging aan haar coördinaten mag het origineel niet veranderen.
is vraagt naar identiteit; == vraagt naar de gekozen gelijkheidsbetekenis.__eq__ vergelijkt alle relevante velden van passende objecten.NotImplemented laat een niet-ondersteunde vergelijking verder afhandelen door Python.Hierna bouw je objecten die andere objecten bevatten en kies je bewust wat zij delen.
Voer je code uit en ontdek
wat je hebt gemaakt.
Je hoeft het niet in één keer goed te doen. Na het uitvoeren zie je hier welke stappen al kloppen.