2012-09-17 10 views
6

Tengo el siguiente código:¿Python coacciona los tipos al realizar una sobrecarga del operador?

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

Pero si hago una subclase de int, y reimplementar __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' 

¿Por qué estos dos diferentes? ¿El tiempo de ejecución de Python captura el TypeError lanzado por int.__cmp__(), e interpretándolo como un valor de False? ¿Puede alguien señalarme un poco en la fuente 2.x cpython que muestra cómo funciona esto?

+0

En una nota al margen: ¿sabes que '__cmp__' estaba en desuso hace siglos? Debe implementar funciones de comparación enriquecida. – Bakuriu

+0

Sí, esto surgió cuando estaba tratando de averiguar si debería presentar una excepción o devolver NotImplemented en una implementación de __eq__. Quería ver lo que hacían las clases integradas de Python, y encontré este ejemplo que parecía inconsistente. – Chris

Respuesta

5

La documentación no es completamente explícito en este punto, pero ver here:

Si ambos son números, que se convierten en un tipo común. De lo contrario, los objetos de diferentes tipos siempre se comparan desiguales, y se ordenan de manera consistente pero arbitraria. Puede controlar el comportamiento de comparación de objetos de tipos no incorporados definiendo un método __cmp__ o métodos de comparación ricos como __gt__, descritos en la sección Nombres de métodos especiales.

Esto (particularmente el contraste implícito entre "objetos de diferentes tipos" y "objetos de tipos no incorporados") sugiere que el proceso normal de llamar realmente a los métodos de comparación se omite para tipos incorporados: Intenta comparar objetos de dos tipos diferentes (y no numéricos) incorporados, solo cortocircuita a un False automático.

-2

Si he entendido su derecha problema, es necesario algo así como:

>>> 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 

Actualizado

En cuanto a la 2.x fuente CPython, se pueden encontrar razón de este resultado en typeobject.c en función de wrap_cmpfunc que en realidad comprueba dos cosas: dada la función de comparación es un func y other es un subtipo para self.

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

No creo que esto aborde la pregunta en absoluto. Creo que OP reconoce que puede forzar el tipo de otro para hacer que la comparación funcione. La pregunta es * ¿por qué tiene que hacerlo? * ¿Por qué no '__cmp__' ve que los tipos no son iguales y devuelve' False' de inmediato? – mgilson

+4

La pregunta es por qué hay dos resultados diferentes, no cómo comparar 'str' e' int'. –

+0

Respuesta actualizada. –

3

Un árbol de comparación de decisión para a == b se ve algo como:

  • llamadas pitón a.__cmp__(b)
    • a cheques que b es un tipo apropiado
    • si b es un tipo apropiado, volver -1, 0, o +1
    • si b es No, volver NotImplented
  • si -1, 0 o +1 regresaron, se hace pitón; de lo contrario
  • si NotImplented volvió, intente
  • b.__cmp__(a)
    • b cheques que a es un tipo apropiado
    • si a es un tipo apropiado, volver -1, 0, o +1
    • si a no es, return NotImplemented
  • si -1, 0, o +1 devuelto, python está hecho; de lo contrario
  • si NotImplented volvió de nuevo, la respuesta es False
No

una respuesta exacta, pero es de esperar que ayude.

+0

Bien, pero no explica el mensaje de error. –