Heim >Backend-Entwicklung >Python-Tutorial >Wie stellen Sie konsistente und robuste Äquivalenzvergleiche für benutzerdefinierte Python-Klassen sicher, insbesondere beim Umgang mit Unterklassen und Mengen?

Wie stellen Sie konsistente und robuste Äquivalenzvergleiche für benutzerdefinierte Python-Klassen sicher, insbesondere beim Umgang mit Unterklassen und Mengen?

Linda Hamilton
Linda HamiltonOriginal
2024-11-09 04:50:02429Durchsuche

How do you ensure consistent and robust equivalence comparisons for custom Python classes, especially when dealing with subclasses and sets?

Elegante Ansätze für den Äquivalenzvergleich in Python-Klassen

In Python können benutzerdefinierte Klassen die Methoden __eq__ und __ne__ implementieren, um Äquivalenz für die Operatoren == und != zu definieren. jeweils. Obwohl die herkömmliche Methode zum Vergleichen von Wörterbuchattributen unkompliziert ist, weist sie gewisse Einschränkungen auf.

Ein verfeinerterer Ansatz

Stellen Sie sich das folgende Szenario vor:

class Number:
    def __init__(self, number):
        self.number = number

n1 = Number(1)
n2 = Number(1)

# Default comparison fails: they are different objects
assert n1 != n2

Um dieses Problem zu beheben , wir können die __eq__-Methode überschreiben:

class Number:
    def __init__(self, number):
        self.number = number

    def __eq__(self, other):
        if isinstance(other, Number):
            return self.number == other.number
        return False

Für Python 2 müssen wir jedoch auch implementieren __ne__, um kommutatives Verhalten sicherzustellen:

class Number:
    def __init__(self, number):
        self.number = number

    def __eq__(self, other):
        if isinstance(other, Number):
            return self.number == other.number
        return False

    def __ne__(self, other):
        return not self.__eq__(other)

Dadurch wird sichergestellt, dass n1 == n2 erwartungsgemäß „True“ ergibt.

Unterklassenäquivalenz

Die Einführung von Unterklassen erschwert den Äquivalenzvergleich:

class SubNumber(Number):
    pass

n3 = SubNumber(1)

# Subclass comparison fails for classic-style classes
assert n1 == n3  # False (for classic-style classes)
assert n3 == n1  # True

# Non-commutative comparison
assert n1 != n3  # True (for classic-style classes)
assert n3 != n1  # False

Für Klassen im klassischen Stil wird die Vergleichsmethode basierend auf aufgerufen Der Typ des ersten Operanden führt zu nicht kommutativem Verhalten. Um dies zu beheben, können wir NotImplemented für nicht unterstützte Operandentypen zurückgeben, wodurch der Vergleich an die Methode des anderen Operanden delegiert wird:

def __eq__(self, other):
    if isinstance(other, Number):
        return self.number == other.number
    return NotImplemented

Hashing und Sets

Zuletzt beachten Sie, dass Sets Objektbezeichner für verwenden Hashing, das zu falschen Ergebnissen führen kann:

assert len(set([n1, n2, n3])) == 3  # Incorrectly reports 3 unique numbers

Um dieses Problem zu beheben, können wir das überschreiben __hash__-Methode:

def __hash__(self):
    return hash(tuple(sorted(self.__dict__.items())))

Mit diesen Verbesserungen wird das Äquivalenz- und Eindeutigkeitsverhalten korrekt und konsistent, was robuste Vergleiche und eine genaue Darstellung in Mengen gewährleistet:

assert len(set([n1, n2, n3])) == 1
assert len(set([n1, n2, n3, n4])) == 2

Das obige ist der detaillierte Inhalt vonWie stellen Sie konsistente und robuste Äquivalenzvergleiche für benutzerdefinierte Python-Klassen sicher, insbesondere beim Umgang mit Unterklassen und Mengen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn