sino relacionales operadores logicos else ejemplos condicional python language-design language-history

logicos - operadores relacionales en python



Python: ¿Por qué la clase int no tiene operadores de comparación ricos como `__lt__()`? (3)

Como dijo hircus, las comparaciones de estilo __cmp__ están en desuso a favor de los operadores enriquecidos ( __lt__ , ...) en Python 3. Originalmente, las comparaciones se implementaron utilizando __cmp__ , pero hay algunos tipos / situaciones donde un simple operador de __cmp__ no es suficiente ( por ejemplo, las instancias de una clase de Color podrían admitir == y != , pero no < o > , por lo que se agregaron los operadores de comparación enriquecidos, dejando __cmp__ en su lugar para la compatibilidad con versiones anteriores. Siguiendo la filosofía de Python de "Debería haber una, y preferiblemente una única forma obvia de hacerlo", 1 el soporte heredado se eliminó en Python 3, cuando se podía sacrificar la compatibilidad hacia atrás.

En Python 2, mientras que int todavía usa __cmp__ para no interrumpir la compatibilidad hacia atrás, no todos los números de punto flotante son menores, mayores o iguales que otros números de punto flotante (por ejemplo, (float(''nan'') < 0.0, float(''nan'') == 0.0, float(''nan'') > 0.0) evalúa como (False, False, False) , entonces, ¿qué debería float(''nan'').__cmp__(0.0) volver?), por lo que float necesita usar Los nuevos operadores de comparación ricos.

1 : Intente escribir "importar esto" en un shell de python.

Mayormente curioso.

He notado (al menos en py 2.6 y 2.7) que un float tiene todas las funciones de comparación ricas: __lt__() , __gt__ , __eq__ , etc.

>>> (5.0).__gt__(4.5) True

pero un int no lo hace

>>> (5).__gt__(4) Traceback (most recent call last): File "<input>", line 1, in <module> AttributeError: ''int'' object has no attribute ''__gt__''

Lo que es extraño para mí, porque el propio operador funciona bien.

>>> 5 > 4 True

Incluso las cadenas soportan las funciones de comparación

>>> "hat".__gt__("ace") True

pero todo lo que tiene int es __cmp__()

Me parece extraño, así que me preguntaba por qué sucedió esto.

Acabo de probarlo y funciona como se espera en Python 3, así que asumo algunas razones heredadas. Sin embargo, me gustaría escuchar una explicación adecuada;)


Si miramos el PEP 207 para las comparaciones ricas, hay una oración interesante al final:

La alineación ya presente que se ocupa de las comparaciones de enteros todavía se aplicaría, resultando en ningún costo de rendimiento para los casos más comunes.

Así que parece que en 2.x hay una optimización para la comparación de enteros. Si echamos un vistazo al código fuente podemos encontrar esto:

case COMPARE_OP: w = POP(); v = TOP(); if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) { /* INLINE: cmp(int, int) */ register long a, b; register int res; a = PyInt_AS_LONG(v); b = PyInt_AS_LONG(w); switch (oparg) { case PyCmp_LT: res = a < b; break; case PyCmp_LE: res = a <= b; break; case PyCmp_EQ: res = a == b; break; case PyCmp_NE: res = a != b; break; case PyCmp_GT: res = a > b; break; case PyCmp_GE: res = a >= b; break; case PyCmp_IS: res = v == w; break; case PyCmp_IS_NOT: res = v != w; break; default: goto slow_compare; } x = res ? Py_True : Py_False; Py_INCREF(x); } else { slow_compare: x = cmp_outcome(oparg, v, w); }

Así que parece que en 2.x existía una optimización de rendimiento existente, al permitir que el código C comparara directamente los enteros, que no se habría conservado si se hubieran implementado los operadores de comparación ricos.

Ahora en Python 3 __cmp__ ya no se admite, por lo que los operadores de comparación ricos deben estar allí. Ahora, esto no causa un impacto en el rendimiento por lo que puedo decir. Por ejemplo, compara:

Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05) [GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import timeit >>> timeit.timeit("2 < 1") 0.06980299949645996

a:

Python 3.2.3 (v3.2.3:3d0686d90f55, Apr 10 2012, 11:25:50) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import timeit >>> timeit.timeit("2 < 1") 0.06682920455932617

Así que parece que existen optimizaciones similares, pero mi conjetura es que la decisión fue que ponerlos a todos en la rama 2.x habría sido un cambio demasiado grande cuando la compatibilidad hacia atrás era una consideración.

En 2.x, si desea algo como los métodos de comparación ricos que puede obtener a través del módulo del operator :

>>> import operator >>> operator.gt(2,1) True


__cmp__() es la manera anticuada de hacer comparaciones, y está en desuso a favor de los operadores ricos ( __lt__ , __le__ etc.) que solo se introdujeron en Python 2.1. Probablemente la transición no se completó en 2.7.x, mientras que en Python 3.x __cmp__ se eliminó por completo.

Haskell tiene la implementación más elegante que he visto: para ser un tipo de datos Ord (ordinal), solo tiene que definir cómo funciona < y = , y el propio typeclass proporciona implementaciones predeterminadas para <= , > y >= en términos de esos dos (que son más que bienvenidos a definirse si lo desean). Puede escribir una clase de este tipo en Python, sin estar seguro de por qué no es el predeterminado; Probablemente razones de rendimiento.