2010-05-14 6 views
5

así que tengo un chiste:de Python para ricos comparación (O bien, cuando decimal ('100,0') <0,01)

import decimal; h = decimal.Decimal('100.0'); (h > .01, h < .01, h.__gt__(.01), h.__lt__(.01)) 

único que hace es hacer un objeto decimal sosteniendo 100,0, y lo compara a .01 (el flotador) de varias maneras.

Mi resultado es:

>>> import decimal; h = decimal.Decimal('100.0'); (h > .01, h < .01, h.__gt__(.01), h.__lt__(.01)) 
(False, True, NotImplemented, NotImplemented) 

A partir de los documentos: "Un método de comparación rica puede devolver el producto único NotImplemented si no implementa la operación durante un par de argumentos dados"

Entonces, realmente hay tres preguntas aquí.

  1. Cuando un método de comparación rico devuelve NotImplemented, ¿qué ocurre? ¿Por qué no plantea una excepción?

  2. Cuando se obtiene NotImplemented, ¿por qué devuelve False en el primer caso y True en el segundo? bool (NotImplemented) debería ser una constante.

  3. ¿Simplemente recurre a la comprobación de id()? Parece que no (o sí, pero al revés):

(ignorar esta línea, el formato se arrugó y esto lo arregla)

from decimal import Decimal 
h = Decimal('100.0') 
f = .01 
print h < f, id(h) < id(f) 
print h > f, id(h) > id(f) 

Mis resultados fueron probados en:

Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32 
Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on win32 

Editar: Documentación sobre el pedido: http://docs.python.org/library/stdtypes.html#comparisons

Respuesta

6

Cuando un método de comparación rico devuelve NotImplemented, ¿qué ocurre? ¿Por qué no genera una excepción?

delega en el método inverso (por ejemplo, __lt__ cuando el operador está >) RHS en la comparación (el float) - que en este caso también devuelve NotImplemented - y, finalmente, cae de nuevo a Python 2 tonta de edad reglas para comparaciones heterogéneas.

cuando se pone NotImplemented, ¿por qué se return false en el primer caso, y True en el segundo? bool (NotImplemented) debe ser una constante .

Sin bool involucrados - desde ambos lados de la comparación vuelven NotImplemented (debido a una decisión de diseño deliberada de no apoyar cualquier operación entre decimales y flotadores), las viejas reglas tontas se utilizan como punto de retorno (y en una la versión lo suficientemente reciente comparará los tipos, no las instancias; id no tiene nada que ver con eso, por lo tanto). En Python 3, una comparación heterogénea no soportada fallaría y generaría una clara excepción, pero en Python 2, por compatibilidad con versiones anteriores, eso simplemente no puede suceder, debe seguir comportándose de la manera tonta en que se comportó durante toda la vida de Python 2.

Presentación de incompatibilidades hacia atrás para arreglar lo que ahora se consideran los errores de diseño, como esta parte sobre las comparaciones het, fue la razón por la núcleo de introducir Python 3. Mientras se está pegando a Python 2 (por ejemplo, porque tiene más extensiones de terceros, etc.), debe sonreír y soportar estas imperfecciones que solo se solucionan en Python 3.

+0

Ah, no sabía sobre la ordenación cruzada del tipo de objeto. Gracias por tu clara explicación. –

+0

Bueno, después de mucho retorcerse las manos y sacar la barba, las reglas se han relajado un poco en Python 2.7: las instancias de decimales y flotantes ahora se comparan sensiblemente entre sí. El principal problema técnico era preservar la regla de que los números que se comparan iguales también deberían ser iguales. (¡No intentes comparar las instancias Decimal y Fraction, sin embargo!) –

0

Tengo Python 2.6.4 y su ejemplo funciona bien , es decir, encuentro

(True, False, NotImplemented, NotImplemented) 

que se espera. No sé por qué obtienes resultados diferentes.

Sobre id: Identificación del no tiene nada que ver con las comparaciones, por lo que bajo ninguna circunstancia se debe comparar a y b por id(a) < id(b), que no tiene ningún sentido. id es un poco como una dirección en la memoria, por lo que compararlos no tiene ningún sentido.

+0

id() se utiliza como último recurso para ordenar objetos si los objetos no definen sus propias comparaciones. No recuerdo exactamente cuándo se usa, pero definitivamente lo es. Tiene razón en que no tiene sentido, a menos que estuviera tratando de garantizar que "los objetos están ordenados de manera consistente pero arbitraria (de modo que ordenar una matriz heterogénea produce un resultado consistente)", que, como señalan los documentos, python hace. –

+0

simplemente funciona de esa manera para usted: pruebe 999.01 en lugar de 0.1 y verá exactamente los mismos resultados, mostrándole que ** no ** "funciona bien" (es un reloj parado: corríjalo dos veces al día ;-). Los _types_ terminan siendo comparados (y estas comparaciones de tipos no necesitan funcionar de la misma manera en diferentes instalaciones de Python), no los _values_ como uno normalmente esperaría. –

+0

@CB, 'id' se usa como el último recurso para las comparaciones _non-ordering_ (igualdad y desigualdad) y hashing, donde tiene perfecto sentido; nunca se usa para comparaciones de orden como '<'. En cambio, las comparaciones de ordenamiento heterogéneas terminan comparando los _types_ en lugar del valor. –