Maison >développement back-end >Tutoriel Python >Comment garantir des comparaisons d'équivalence cohérentes et robustes pour les classes Python personnalisées, en particulier lorsqu'il s'agit de sous-classes et d'ensembles ?

Comment garantir des comparaisons d'équivalence cohérentes et robustes pour les classes Python personnalisées, en particulier lorsqu'il s'agit de sous-classes et d'ensembles ?

Linda Hamilton
Linda Hamiltonoriginal
2024-11-09 04:50:02455parcourir

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

Approches élégantes pour la comparaison d'équivalence dans les classes Python

En Python, les classes personnalisées peuvent implémenter les méthodes __eq__ et __ne__ pour définir l'équivalence pour les opérateurs == et !=, respectivement. Bien que la méthode traditionnelle de comparaison des attributs du dictionnaire soit simple, elle présente certaines limites.

Une approche plus raffinée

Considérez le scénario suivant :

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

Pour résoudre ce problème , nous pouvons remplacer la méthode __eq__ :

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

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

Cependant, pour Python 2, nous devons également implémenter __ne__ pour garantir un comportement commutatif :

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)

Cela garantit que n1 == n2 est évalué à True, comme prévu.

Équivalence des sous-classes

L'introduction de sous-classes complique la comparaison d'équivalence :

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

Pour les classes de style classique, la méthode de comparaison est invoquée en fonction de la type du premier opérande, conduisant à un comportement non commutatif. Pour résoudre ce problème, nous pouvons renvoyer NotImplemented pour les types d'opérandes non pris en charge, ce qui délègue la comparaison à la méthode de l'autre opérande :

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

Hashing et Sets

Enfin, notez que les ensembles utilisent des identifiants d'objet pour hachage, ce qui peut conduire à des résultats incorrects :

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

Pour résoudre ce problème, nous pouvons remplacer la méthode __hash__ :

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

Avec ces améliorations, les comportements d'équivalence et d'unicité deviennent corrects et cohérent, garantissant des comparaisons robustes et une représentation précise dans les ensembles :

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn