0%

Objecten weergeven en vergelijken · oefening

Hash alleen stabiele waarden

Het definiëren van __eq__ heeft ongemerkt iets veranderd. Probeer een gelijke waarde in een set te zetten:

class Points:
    def __init__(self, amount):
        self.amount = amount

    def __eq__(self, other):
        if not isinstance(other, Points):
            return NotImplemented
        return self.amount == other.amount


{Points(3)}

Python meldt TypeError: unhashable type: 'Points'.

Gelijkheid en hashing moeten overeenstemmen

Sets en dictionaries vinden een object met een getal dat de hash heet. Gelijke objecten moeten gelijke hashes opleveren. Voordat __eq__ werd gedefinieerd, leverde identiteit zowel gelijkheid als hashing, dus die stemden overeen.

Een op inhoud gebaseerde __eq__ verbreekt die overeenstemming. Python schakelt hashing uit in plaats van toe te laten dat een set gelijke waarden kwijtraakt.

Waarom maakt het definiëren van __eq__ zonder een bijpassende __hash__ deze klasse onbruikbaar als dictionarysleutel?

Herstel hashing alleen voor stabiele waarden

Definieer __hash__ over precies de toestand die gelijkheid vergelijkt:

Try it

De alleen-lezen property houdt de ondersteunde publieke interface stabiel. Als amount na het invoegen zou veranderen, zou de hash naar een andere plek wijzen en kan het opzoeken mislukken terwijl het object nog aanwezig is. Een underscore aan het begin blijft een conventie, geen afdwinging; hoofdstuk 8 introduceert een bevroren waarde waarvan Python zelf wijzigingen weigert.

Bij meerdere vergeleken attributen hash je dezelfde tuple die gelijkheid vergelijkt:

def __hash__(self):
    return hash((self.prompt, self.answer, self.points))

Welke klasse kun je veilig op basis van de inhoud hashen?

Hashing is geen beloning die elke waarde nodig heeft. Voeg het alleen toe als sets of dictionarysleutels echt bij het gebruik van de klasse horen en alleen als de vergeleken toestand niet kan veranderen.

De oefening maakt Points en Question veilig hashbaar. Ordening is een andere ontwerpbeslissing, die hierna aan bod komt.

Opdracht

Maak de twee alleen-lezen waarden veilig hashbaar.

Geef Points een __eq__ en bijpassende __hash__ op basis van amount.

Geef Question een __eq__ en bijpassende __hash__ op basis van prompt, answer en points.

Beide gelijkheidsmethoden geven NotImplemented terug voor een ander type. Voeg nog geen ordeningsmethoden toe.