2012-09-17 8 views
6

Ho il seguente codice:I tipi di coerce di Python eseguono un sovraccarico dell'operatore?

a = str('5') 
b = int(5) 
a == b 
# False 

Ma se faccio una sottoclasse di int, e reimplementare __cmp__:

class A(int): 
    def __cmp__(self, other): 
     return super(A, self).__cmp__(other) 
a = str('5') 
b = A(5) 
a == b 
# TypeError: A.__cmp__(x,y) requires y to be a 'A', not a 'str' 

perché queste due differenti? Il runtime python rileva l'errore TypeError di int.__cmp__() e l'interpreta come valore False? Qualcuno può indicarmi il bit nella fonte cpython 2.x che mostra come funziona?

+0

Nota a margine: si sa che '__cmp__' è stato deprecato anni fa? Dovresti implementare funzioni di confronto avanzato. – Bakuriu

+0

Sì, questo è venuto fuori quando stavo cercando di capire se avrei dovuto sollevare un'eccezione o restituire NotImplemented in un'implementazione di __eq__. Volevo vedere cosa facevano le classi Python e ho trovato questo esempio che sembrava incoerente. – Chris

risposta

5

La documentazione non è del tutto esplicito su questo punto, ma si veda here:

Se entrambi sono numeri, vengono convertiti in un tipo comune. Altrimenti, gli oggetti di diverso tipo si confrontano sempre in modo diseguale e ordinati in modo coerente ma arbitrario. È possibile controllare il comportamento di confronto degli oggetti di tipi non integrati definendo un metodo __cmp__ o metodi di confronto avanzati come __gt__, descritti nella sezione Nomi dei metodi speciali.

Questa (in particolare la implicito contrasto tra "oggetti di diversi tipi" e "oggetti di non incorporato tipi") suggerisce che il processo normale di realtà chiamata metodi di confronto viene saltato tipi predefiniti: se si tenta di confrontare gli oggetti di due tipi predefiniti dfferent (e non numerici), ma solo cortocircuiti verso un False automatico.

-2

Se ho capito il problema giusto, è necessario qualcosa di simile:

>>> class A(int): 
...  def __cmp__(self, other): 
...   return super(A, self).__cmp__(A(other)) # <--- A(other) instead of other 
... 
>>> a = str('5') 
>>> b = A(5) 
>>> a == b 
True 

Aggiornato

Riguardo al 2.x fonte CPython, si possono trovare motivo di questo risultato in typeobject.c in funzione wrap_cmpfunc che in realtà controlla due cose: la funzione di confronto data è una func e other è sottotipo per self.

if (Py_TYPE(other)->tp_compare != func && 
    !PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self))) { 
// .... 
} 
+3

Non penso che questo risolva la domanda. Penso che OP riconosca di poter forzare il tipo dell'altro per far funzionare il confronto. La domanda è * perché deve? * Perché '__cmp__' non vede che i tipi non sono gli stessi e restituiscono' False' subito? – mgilson

+4

La domanda è: perché ci sono due risultati diversi, non come fare il confronto tra 'str' e' int'. –

+0

Risposta aggiornata. –

3

un albero decisionale confronto per a == b simile a:

  • chiamate pitone a.__cmp__(b)
    • a controlli che b è un tipo appropriato
    • se b è un tipo appropriato, tornare -1, 0, o +1
    • se b è no, tornare NotImplented
  • se -1, 0 o +1 restituito, pitone è fatto; altrimenti
  • se NotImplented tornato, provare
  • b.__cmp__(a)
    • b controlla che a è un tipo appropriato
    • se a è un tipo appropriato, tornare -1, 0, o +1
    • se a non è, ritorno NotImplemented
  • se -1, 0 o +1 restituito, Python è terminato; altrimenti
  • se NotImplented tornato ancora una volta, la risposta è False
Non

una risposta esatta, ma si spera che aiuta.

+0

Nice, ma non spiega il messaggio di errore. –

Problemi correlati