programar - sintaxis python
¿Por qué Python no tiene una función de signo? (10)
"Copysign" está definido por IEEE 754 y parte de la especificación C99. Es por eso que está en Python. La función no se puede implementar en su totalidad por abs (x) * sign (y) debido a cómo se supone que debe manejar los valores de NaN.
>>> import math
>>> math.copysign(1, float("nan"))
1.0
>>> math.copysign(1, float("-nan"))
-1.0
>>> math.copysign(float("nan"), 1)
nan
>>> math.copysign(float("nan"), -1)
nan
>>> float("nan") * -1
nan
>>> float("nan") * 1
nan
>>>
Eso hace que copysign () sea una función más útil que sign ().
En cuanto a las razones específicas por las cuales el signo de IEEE (x) no está disponible en Python estándar, no lo sé. Puedo hacer suposiciones, pero sería adivinar.
El módulo matemático en sí mismo usa signbit (1, x) como una forma de verificar si x es negativo o no negativo. En la mayoría de los casos, se trata de funciones matemáticas que parecen más útiles que tener un signo (x) que devuelve 1, 0 o -1 porque hay un caso menos que considerar. Por ejemplo, lo siguiente es del módulo matemático de Python:
static double
m_atan2(double y, double x)
{
if (Py_IS_NAN(x) || Py_IS_NAN(y))
return Py_NAN;
if (Py_IS_INFINITY(y)) {
if (Py_IS_INFINITY(x)) {
if (copysign(1., x) == 1.)
/* atan2(+-inf, +inf) == +-pi/4 */
return copysign(0.25*Py_MATH_PI, y);
else
/* atan2(+-inf, -inf) == +-pi*3/4 */
return copysign(0.75*Py_MATH_PI, y);
}
/* atan2(+-inf, x) == +-pi/2 for finite x */
return copysign(0.5*Py_MATH_PI, y);
Allí puede ver claramente que copysign () es una función más efectiva que una función de signo () de tres valores.
Tu escribiste:
Si yo fuera un diseñador de Python, estaría de otra manera: no incluye cmp (), sino un signo ()
Eso significa que no sabes que cmp () se usa para cosas además de números. cmp ("Esto", "Eso") no se puede implementar con una función de signo ().
Editar para cotejar mis respuestas adicionales en otro lugar :
Basas tus justificaciones en cómo abs () y sign () se ven a menudo juntos. Como la biblioteca estándar de C no contiene ninguna función de ''signo (x)'' de ningún tipo, no sé cómo justificas tus puntos de vista. Hay un abs (int) y fabs (doble) y fabsf (float) y fabsl (long) pero no se menciona el signo. Hay "copysign ()" y "signbit ()" pero solo se aplican a los números IEEE 754.
Con números complejos, ¿qué debería firmar (-3 + 4j) en Python si se implementara? abs (-3 + 4j) return 5.0. Ese es un claro ejemplo de cómo abs () puede usarse en lugares donde sign () no tiene sentido.
Supongamos que el signo (x) se agregó a Python, como complemento de abs (x). Si ''x'' es una instancia de una clase definida por el usuario que implementa el método __abs__ (self) entonces abs (x) llamará a x .__ abs __ (). Para que funcione correctamente, para manejar abs (x) de la misma manera, Python tendrá que ganar un espacio de signo (x).
Esto es excesivo para una función relativamente innecesaria. Además, ¿por qué debería existir el signo (x) y no existir el no negativo (x) y el no positivo (x)? Mi fragmento de la implementación del módulo matemático de Python muestra cómo se puede usar copybit (x, y) para implementar nonnegative (), que un simple signo (x) no puede hacer.
Python debería ser compatible con un mejor soporte para la función matemática IEEE 754 / C99. Eso agregaría una función signbit (x), que haría lo que quieras en el caso de los flotadores. No funcionaría para números enteros o complejos, mucho menos cadenas, y no tendría el nombre que está buscando.
Usted pregunta "por qué", y la respuesta es "sign (x) no es útil". Usted afirma que es útil. Sin embargo, sus comentarios muestran que no sabe lo suficiente como para poder hacer esa afirmación, lo que significa que tendría que mostrar pruebas convincentes de su necesidad. Decir que NumPy lo implementa no es lo suficientemente convincente. Debería mostrar casos de cómo el código existente se mejoraría con una función de signo.
Y que está fuera del alcance de StackOverflow. Tómelo en cambio a una de las listas de Python.
No puedo entender por qué Python no tiene una función de sign
. Tiene un abs
incorporado (que considero la hermana de la sign
), pero no tiene sign
.
En Python 2.6 hay incluso una función de copysign
(en math ), pero no hay señal. ¿Por qué molestarse en escribir una copysign(x,y)
cuando podría simplemente escribir un sign
y luego obtener la copysign
directamente de abs(x) * sign(y)
? Este último sería mucho más claro: x con el signo de y, mientras que con copysign tienes que recordar si es x con el signo de y o y con el signo de x.
Obviamente, sign(x)
no proporciona nada más que cmp(x,0)
, pero sería mucho más legible que esto también (y para un lenguaje muy legible como python, esto habría sido una gran ventaja).
Si yo fuera un diseñador de Python, habría sido al revés: no se trata de un cmp
incorporado, sino de un sign
. Cuando necesitas cmp(x,y)
, puedes hacer un sign(xy)
(o, mejor aún para cosas no numéricas, simplemente ax> y - por supuesto, esto debería haber requerido una aceptación sorted
un booleano en lugar de un comparador entero ) Esto también sería más claro: positivo cuando x>y
(mientras que con cmp
tiene que recordar la convención positiva cuando la primera es más grande , pero podría ser al revés). Por supuesto, cmp
tiene sentido por sí mismo por otras razones (por ejemplo, al ordenar elementos no numéricos, o si desea que el género sea estable, lo que no es posible con simplemente usar un booleano)
Entonces, la pregunta es: ¿por qué los diseñadores de Python decidieron dejar la función de sign
fuera del lenguaje? ¿Por qué diablos molestarse con copysign
y no su sign
principal?
¿Me estoy perdiendo de algo?
EDITAR - después de comentar Peter Hansen. Es suficiente decir que no lo usaste, pero no dijiste para qué usas Python. ¡En 7 años que utilizo Python, lo necesité innumerables veces, y el último es la gota que colmó el vaso!
Sí, puedes pasar cmp, pero el 90% de las veces que necesité pasarlo fue en una expresión idiomática como lambda x,y: cmp(score(x),score(y))
que hubiera funcionado bien con el cartel. .
Finalmente, espero que esté de acuerdo en que el sign
sería más útil que el copysign
, por lo tanto, incluso si compré su vista, ¿por qué molestarse en definir eso en matemáticas, en lugar de firmar? ¿Cómo puede copysign ser tan útil que firmar?
Desde que se removed cmp
, puede obtener la misma funcionalidad con
def cmp(a, b):
return (a > b) - (a < b)
def sign(a):
return (a > 0) - (a < 0)
Funciona para float
, int
e incluso Fraction
. En el caso de float
, el sign(float("nan"))
aviso sign(float("nan"))
es cero.
Python no requiere que las comparaciones devuelvan un booleano, por lo que forzar las comparaciones con bool () protege contra la implementación permisible, pero poco común:
def sign(a):
return bool(a > 0) - bool(a < 0)
El motivo por el que "signo" no está incluido es que si incluimos todos los trazos de una línea útil en la lista de funciones integradas, Python no sería fácil ni práctico de trabajar. Si usa esta función tan a menudo, ¿por qué no hace un factor por sí mismo? No es remotamente difícil o incluso tedioso hacerlo.
En Python 2, cmp () devuelve un número entero: no es necesario que el resultado sea -1, 0 o 1, por lo que sign (x) no es lo mismo que cmp (x, 0).
En Python 3, se eliminó cmp () a favor de la comparación enriquecida. Para cmp (), Python 3 sugiere ( https://docs.python.org/3/whatsnew/3.0.html ):
def cmp(a, b):
return (a > b) - (a < b)
lo cual está bien para cmp (), pero nuevamente no se puede usar para sign () porque los operadores de comparación no necesitan devolver booleanos ( possibility ) .
Para hacer frente a esta posibilidad, los resultados de comparación deben ser coercionados a booleanos:
def sign(a):
return bool(x > 0) - bool(x < 0)
Esto funciona para cualquier tipo que esté totalmente ordenado (incluidos valores especiales como NaN o infinitos).
Intenta ejecutar esto, donde x es cualquier número
int_sign = bool(x > 0) - bool(x < 0)
La coacción a bool () maneja la possibility que el operador de comparación no devuelva un booleano.
No necesitas uno, solo puedes usar:
If not number == 0:
sig = number/abs(number)
else:
sig = 0
Otro trazador de líneas para el signo ()
sign = lambda x: (1, -1)[x<0]
Si desea que devuelva 0 para x = 0:
sign = lambda x: x and (1, -1)[x<0]
Sí, una función de en.wikipedia.org/wiki/Sign_function correcto en.wikipedia.org/wiki/Sign_function debe estar al menos en el módulo matemático, ya que está en numpy. Porque con frecuencia se necesita para el código orientado a las matemáticas.
Pero math.copysign()
también es útil de forma independiente.
cmp()
y obj.__cmp__()
... generalmente tienen una gran importancia de forma independiente. No solo para el código orientado a las matemáticas. Considere la posibilidad de comparar / clasificar tuplas, objetos de fecha, ...
Los argumentos dev en http://bugs.python.org/issue1640 respecto a la omisión de math.sign()
son impares, porque:
- No hay
-NaN
separado -
sign(nan) == nan
sin preocupaciones (comoexp(nan)
) -
sign(-0.0) == sign(0.0) == 0
sin preocupaciones -
sign(-inf) == -1
sin preocupaciones
- como está en numpy
numpy tiene una función de signo, y también te da una bonificación de otras funciones. Asi que:
import numpy as np
x = np.sign(y)
Solo tenga cuidado de que el resultado sea un numpy.float64:
>>> type(np.sign(1.0))
<type ''numpy.float64''>
Para cosas como json, esto importa, ya que json no sabe cómo serializar tipos numpy.float64. En ese caso, podrías hacer:
float(np.sign(y))
para obtener un flotador regular
EDITAR:
De hecho, había un patch que incluía el sign()
en math , pero no fue aceptado, porque no acordaron qué debería devolver en todos los casos extremos (+/- 0, +/- nan, etc.)
Por lo tanto, decidieron implementar solo copysign, que (aunque más detallado) se puede usar para delegar al usuario final el comportamiento deseado para casos extremos , lo que a veces puede requerir la llamada a cmp(x,0)
.
No sé por qué no está incorporado, pero tengo algunas ideas.
copysign(x,y):
Return x with the sign of y.
Lo más importante, copysign
es un superconjunto de sign
! Llamar copysign
con x = 1 es lo mismo que una función de sign
. Entonces podrías usar copysign
y olvidarte de eso .
>>> math.copysign(1, -4)
-1.0
>>> math.copysign(1, 3)
1.0
Si se harta de pasar dos argumentos completos, puede implementar el sign
esta manera, y seguirá siendo compatible con las cosas IEEE mencionadas por otros:
>>> sign = functools.partial(math.copysign, 1) # either of these
>>> sign = lambda x: math.copysign(1, x) # two will work
>>> sign(-4)
-1.0
>>> sign(3)
1.0
>>> sign(0)
1.0
>>> sign(-0.0)
-1.0
>>> sign(float(''nan''))
-1.0
En segundo lugar, generalmente cuando quieres el signo de algo, terminas multiplicándolo con otro valor. Y, por supuesto, eso es básicamente lo que hace copysign
.
Entonces, en lugar de:
s = sign(a)
b = b * s
Puedes hacer:
b = copysign(b, a)
Y sí, me sorprende que hayas usado Python durante 7 años y pienses que cmp
podría ser eliminado tan fácilmente y reemplazado por un sign
. ¿Nunca has implementado una clase con un método __cmp__
? ¿Nunca ha llamado a cmp
y ha especificado una función de comparador personalizada?
En resumen, me he encontrado queriendo una función de sign
también, pero copysign
con el primer argumento siendo 1 funcionará muy bien. No estoy de acuerdo con que el sign
sea más útil que copysign
, ya que he demostrado que es simplemente un subconjunto de la misma funcionalidad.