__str__ - getattr python
¿Por qué/Cuándo en Python hace `x== y` llamada` y.__ eq__(x) `? (4)
¿Esto no está documentado en la Referencia del lenguaje ? Solo con una mirada rápida, parece que __cmp__
se ignora cuando __eq__
, __lt__
, etc. están definidos. Estoy entendiendo eso para incluir el caso donde __eq__
se define en una clase para padres. str.__eq__
ya está definido así que __cmp__
en sus subclases será ignorado. object.__eq__
etc. no están definidos, por lo que __cmp__
en sus subclases se cumplirán.
En respuesta a la pregunta aclarada:
Sé que
__eq__
se llama en preferencia a__cmp__
, pero no estoy claro por quéy.__eq__(x)
se llama con preferencia ax.__eq__(y)
, cuando este último es lo que el estado de los documentos ocurrirá.
Los documentos dicen que x.__eq__(y)
se llamará primero, pero tiene la opción de devolver NotImplemented
en cuyo caso se llama y.__eq__(x)
. No estoy seguro de por qué confías en que algo diferente está sucediendo aquí.
¿En qué caso estás específicamente desconcertado? Estoy entendiendo que solo estás confundido sobre los casos "b" == tsc
y tsc == "b"
, ¿correcto? En cualquier caso, str.__eq__(onething, otherthing)
se está llamando. Como no anulas el método __eq__
en TestStrCmp, finalmente __eq__
método de la cadena base y te dice que los objetos no son iguales.
Sin conocer los detalles de implementación de str.__eq__
, no sé si ("b").__eq__(tsc)
devolverá NotImplemented
y le dará a tsc la oportunidad de manejar la prueba de igualdad. Pero incluso si lo hiciera, la forma en que tiene TestStrCmp definido, aún obtendrá un resultado falso.
Entonces no está claro lo que estás viendo aquí que es inesperado.
Quizás lo que está sucediendo es que Python está prefiriendo __eq__
a __cmp__
si está definido en cualquiera de los objetos que se comparan, mientras que usted esperaba que __cmp__
en el objeto __cmp__
a la izquierda tenga prioridad sobre __eq__
en el objeto derecho. ¿Es asi?
Los documentos de Python indican claramente que x==y
llama x.__eq__(y)
. Sin embargo, parece que bajo muchas circunstancias, lo opuesto es verdad. Dónde está documentado cuándo o por qué sucede esto, y cómo puedo averiguar con certeza si los métodos __cmp__
o __eq__
mi objeto __cmp__
llamados.
Editar: Solo para aclarar, sé que __eq__
se llama en preferencia a __cmp__
, pero no estoy claro por qué y.__eq__(x)
se llama con preferencia a x.__eq__(y)
, cuando este último es lo que dice el documento pasará.
>>> class TestCmp(object):
... def __cmp__(self, other):
... print "__cmp__ got called"
... return 0
...
>>> class TestEq(object):
... def __eq__(self, other):
... print "__eq__ got called"
... return True
...
>>> tc = TestCmp()
>>> te = TestEq()
>>>
>>> 1 == tc
__cmp__ got called
True
>>> tc == 1
__cmp__ got called
True
>>>
>>> 1 == te
__eq__ got called
True
>>> te == 1
__eq__ got called
True
>>>
>>> class TestStrCmp(str):
... def __new__(cls, value):
... return str.__new__(cls, value)
...
... def __cmp__(self, other):
... print "__cmp__ got called"
... return 0
...
>>> class TestStrEq(str):
... def __new__(cls, value):
... return str.__new__(cls, value)
...
... def __eq__(self, other):
... print "__eq__ got called"
... return True
...
>>> tsc = TestStrCmp("a")
>>> tse = TestStrEq("a")
>>>
>>> "b" == tsc
False
>>> tsc == "b"
False
>>>
>>> "b" == tse
__eq__ got called
True
>>> tse == "b"
__eq__ got called
True
Editar: De la respuesta y el comentario de Mark Dickinson, parece que:
- La comparación rica anula
__cmp__
-
__eq__
es su propia__rop__
a su__op__
(y similar para__lt__
,__ge__
, etc.) - Si el objeto izquierdo es una clase incorporada o de estilo nuevo, y la derecha es una subclase de la misma, se intenta
__rop__
del objeto__rop__
antes de que__op__
del objeto izquierdo
Esto explica el comportamiento en los ejemplos de TestStrCmp
. TestStrCmp
es una subclase de str
pero no implementa su propio __eq__
por lo que el __eq__
de str
tiene prioridad en ambos casos (es decir, tsc == "b"
llama b.__eq__(tsc)
como __rop__
causa de la regla 1).
En los ejemplos de TestStrEq
, se llama tse.__eq__
en ambas instancias porque TestStrEq
es una subclase de str
y, por lo tanto, se TestStrEq
con preferencia.
En los ejemplos de TestEq
, TestEq
implementa __eq__
y int
no, por lo que __eq__
se llama ambas veces (regla 1).
Pero todavía no entiendo el primer ejemplo con TestCmp
. tc
no es una subclase en int
por lo que debe invocarse AFAICT 1.__cmp__(tc)
, pero no lo es.
Como sé, __eq__()
es un método llamado "comparación enriquecida", y se llama para operadores de comparación con preferencia a __cmp__()
continuación. __cmp__()
si no se define "comparación rica".
Entonces en A == B:
Si __eq__()
se define en A, se llamará
Else __cmp__()
se llamará
__eq__()
definido en ''str'' por lo que su función __cmp__()
no fue llamada.
La misma regla es para __ne__(), __gt__(), __ge__(), __lt__()
y __le__()
métodos de "comparación rica".
En realidad, en los docs , dice:
[
__cmp__
es c] alled por operaciones de comparación si la comparación rica (ver arriba) no está definida.
__eq__
es un método de comparación rico y, en el caso de TestCmp
, no está definido, de ahí la vocación de __cmp__
Falta una excepción clave al comportamiento habitual: cuando el operando de la derecha es una instancia de una subclase de la clase del operando de la izquierda, primero se llama al método especial para el operando de la derecha.
Ver la documentación en:
http://docs.python.org/reference/datamodel.html#coercion-rules
y en particular, los dos párrafos siguientes:
Para los objetos
y
, primero se intentax.__op__(y)
. Si esto no se implementa o devuelveNotImplemented
, seNotImplemented
y.__rop__(x)
. Si esto tampoco se implementa o devuelveNotImplemented
, seNotImplemented
una excepción TypeError. Pero mira la siguiente excepción:Excepción al elemento anterior: si el operando izquierdo es una instancia de un tipo incorporado o una clase de estilo nuevo, y el operando derecho es una instancia de una subclase adecuada de ese tipo o clase y anula el método
__rop__()
la base , el método__rop__()
del operando correcto se prueba antes del método__rop__()
del operando izquierdo.