2016-07-18 126 views
5
class Inner(): 

    def __init__(self, x): 
     self.x = x 

    def __eq__(self, other): 
     if isinstance(other, Inner): 
      return self.x == other.x 
     else: 
      raise TypeError("Incorrect type to compare") 

class Outer(): 

    def __init__(self, y): 
     self.y = Inner(y) 

    def __eq__(self, other): 
     if isinstance(other, Outer): 
      return self.y == other.y 
     elif isinstance(other, Inner): 
      return self.y == other 
     else: 
      raise TypeError("Incorrect type to compare") 


if __name__ == "__main__": 

    a = Outer(1) 
    b = Inner(1) 

    print(a == b) # ok no problem 
    print(b == a) # This will raise a type error 

Nell'esempio ho classe interna ed esterna. Non ho il controllo su ciò che gli strumenti interni volevano semplicemente simulare la situazione. Ho solo il controllo sul comportamento di Outer. Voglio che le istanze esterne possano essere confrontate con le istanze interne (non solo l'uguaglianza). Con l'implementazione data funziona solo il primo confronto perché chiama il metodo __eq__ di Outer consentito per essere confrontato con le istanze Outer e Inner ma il secondo sta chiamando Inner's __eq__ che non consente il confronto con Outer - diamine che non lo so Esterno esiste perché dovrebbe preoccuparsi di implementarlo. C'è un modo per far funzionare il secondo tipo di confronto, con qualcosa di simile allo __radd__ e tali funzioni. Lo so per esempio in C++ risolvilo con definizioni di operatori in linea, ma non ne abbiamo in Python.Operatore di confronto 'inverso' in Python

risposta

2

Non posizionarlo troppo bene: Inner.__eq__ è rotto. Come minimo, anziché generare un errore dovrebbe return NotImplemented, che consentirebbe Python per provare il confronto inverso:

Quando NotImplemented viene restituito, l'interprete quindi provare il riflette operazione sull'altro tipo, o qualche altro fallback, a seconda dell'operatore. Se tutte le operazioni tentate restituiscono NotImplemented, l'interprete genera un'eccezione appropriata.

Meglio ancora sarebbe usare "duck typing", piuttosto che insistere su una specifica classe (a meno che la classe, piuttosto che la sua interfaccia, è una parte esplicitamente importante del confronto):

def __eq__(self, other): 
    try: 
     return self.x == other.x 
    except AttributeError: 
     return NotImplemented 

Tuttavia, come dici tu non puoi controllare questo, dovrai implementare manualmente funzionalità simili, ad esempio:

def compare(a, b): 
    """'Safe' comparison between two objects.""" 
    try: 
     return a == b 
    except TypeError: 
     return b == a 

in quanto non esiste una cosa come __req__ in Python's data model.