Dado un objeto de Python arbitrario, ¿cuál es la mejor manera de determinar si es un número? Aquí is
se define como acts like a number in certain circumstances
.
Por ejemplo, digamos que está escribiendo una clase de vector. Si se le da otro vector, desea encontrar el producto escalar. Si se le da un escalar, desea escalar todo el vector.
Comprobación de si algo es int
, float
, long
, bool
es molesto y no cubre los objetos definidos por el usuario que podrían actuar como números. Pero buscar __mul__
, por ejemplo, no es lo suficientemente bueno porque la clase de vector que acabo de describir definiría __mul__
, pero no sería el tipo de número que quiero.
isinstance(value, Number) and type(value) != bool
Quieres comprobar si algún objeto
Si está utilizando Python 2.5 o anterior, la única forma real es verificar algunas de esas "ciertas circunstancias" y ver.
En 2.6 o superior, puede usar
isinstance
con números . Número : una clase base abstracta (ABC) que existe exactamente para este propósito (existen muchos más ABC en elcollections
módulo para varias formas de colecciones / contenedores, nuevamente comenzando con 2.6; y, Además, solo en esas versiones, puede agregar fácilmente sus propias clases base abstractas si es necesario).Bach a 2.5 y anteriores, "se puede agregar
0
y no es iterable" podría ser una buena definición en algunos casos. Pero, realmente debe preguntarse qué es lo que está preguntando que lo que quiere considerar "un número" definitivamente debe poder hacer , y qué debe ser absolutamente incapaz de hacer, y verificar.Esto también puede ser necesario en 2.6 o posterior, quizás con el propósito de hacer sus propios registros para agregar los tipos que le interesan y en los que aún no se han registrado
numbers.Numbers
, si desea excluir algunos tipos que afirman que son números, pero usted simplemente no puedo manejar, eso requiere aún más cuidado, ya que los ABC no tienen ningúnunregister
método [[por ejemplo, puede hacer su propio ABCWeirdNum
y registrar allí todos los tipos extraños para usted, luego primero verifiqueisinstance
que estén disponibles antes de continuar a la comprobaciónisinstance
de lo normalnumbers.Number
para continuar con éxito.Por cierto, siempre que necesite verificar si
x
puede o no puede hacer algo, generalmente debe probar algo como:La presencia de
__add__
per se no le dice nada útil, ya que, por ejemplo, todas las secuencias lo tienen con el propósito de concatenación con otras secuencias. Esta comprobación es equivalente a la definición "un número es algo tal que una secuencia de tales cosas es un único argumento válido para la función incorporadasum
", por ejemplo. Los tipos totalmente extraños (por ejemplo, los que generan la excepción "incorrecta" cuando se suman a 0, como, por ejemplo, aZeroDivisionError
oValueError
& c) propagarán la excepción, pero está bien, deje que el usuario sepa lo antes posible que esos tipos locos simplemente no son aceptables en el bien empresa;-); pero, un "vector" que se puede sumar a un escalar (la biblioteca estándar de Python no tiene uno, pero por supuesto son populares como extensiones de terceros) también daría un resultado incorrecto aquí, así que (por ejemplo,el "no permitido que sea iterable" (por ejemplo, verificar queiter(x)
aumenteTypeError
, o la presencia de un método especial__iter__
, si está en 2.5 o antes y, por lo tanto, necesita sus propias verificaciones).Un breve vistazo a tales complicaciones puede ser suficiente para motivarte a confiar en clases base abstractas siempre que sea posible ... ;-).
fuente
Este es un buen ejemplo en el que las excepciones realmente brillan. Simplemente haga lo que haría con los tipos numéricos y obtenga el
TypeError
de todo lo demás.Pero obviamente, esto solo verifica si una operación funciona , ¡no si tiene sentido ! La única solución real para eso es nunca mezclar tipos y siempre saber exactamente a qué clase de tipos pertenecen sus valores.
fuente
isinstance
puede ser realmente útil en muchos casos (== "comprobar que tiene sentido", así como la aplicabilidad formal de operaciones). Cambio difícil para las personas que solo usan Python desde hace mucho tiempo, pero una tendencia sutil muy importante en la filosofía de Python que sería un error grave ignorar.collections.Sequence
y amigos). Pero afaik, no existen tales clases para números, vectores o cualquier otro objeto matemático.Multiplica el objeto por cero. Cualquier número multiplicado por cero es cero. Cualquier otro resultado significa que el objeto no es un número (incluidas las excepciones)
El uso de isNumber de esta manera dará el siguiente resultado:
Salida:
Probablemente hay algunos objetos no numéricos en el mundo que definen
__mul__
devolver cero cuando se multiplica por cero, pero esa es una excepción extrema. Esta solución debe cubrir todo lo normal y sano. código que genere / encuentre.Ejemplo de numpy.array:
salida:
fuente
True * 0 == 0
int
por lo que mi función dirá correctamente que los booleanos son números.Para reformular su pregunta, está tratando de determinar si algo es una colección o un valor único. Tratar de comparar si algo es un vector o un número es comparar manzanas con naranjas: puedo tener un vector de cadenas o números, y puedo tener una sola cadena o un solo número. Le interesa cuántos tiene (1 o más) , no qué tipo tiene realmente.
mi solución para este problema es verificar si la entrada es un valor único o una colección al verificar la presencia de
__len__
. Por ejemplo:O, para el enfoque de tipificación de pato, puede intentar iterar
foo
primero:En última instancia, es más fácil probar si algo es similar a un vector que probar si algo es similar a un escalar. Si tiene valores de diferente tipo (es decir, cadena, numérico, etc.), entonces la lógica de su programa puede necesitar algo de trabajo. ¿Cómo terminó tratando de multiplicar una cadena por un vector numérico en primer lugar?
fuente
Para resumir / evaluar los métodos existentes:
(Vine aquí por esta pregunta )
Código
fuente
float('nan'), 'nan', '123.45', '42', '42a', '0x8', '0xa'
agregarmath.isnan
Probablemente sea mejor hacerlo al revés: comprueba si es un vector. Si es así, realiza un producto escalar y en todos los demás casos intenta la multiplicación escalar.
Verificar el vector es fácil, ya que debe ser de su tipo de clase de vector (o heredado de él). También puede intentar primero hacer un producto punto, y si eso falla (= no era realmente un vector), luego recurrir a la multiplicación escalar.
fuente
Solo para agregar. Quizás podamos usar una combinación de isinstance e isdigit de la siguiente manera para encontrar si un valor es un número (int, float, etc.)
si isinstance (num1, int) o isinstance (num1, float) o num1.isdigit ():
fuente
Para la clase de vector hipotética:
Supongamos que
v
es un vector y lo multiplicamos porx
. Si tiene sentido multiplicar cada componente dev
porx
, probablemente lo decimos en serio, así que inténtalo primero. Si no es así, ¿quizás podamos puntear? De lo contrario, es un error de tipo.EDITAR : el siguiente código no funciona, porque en
2*[0]==[0,0]
lugar de generar unTypeError
. Lo dejo porque fue comentado.fuente
x
es un vector, entonces se[comp * x for comp in self]
obtendrá el producto externo dex
anv
. Este es un tensor de rango 2, no un escalar.comp*x
va a escalarx
porcomp
, estaba asumiendo que plantearía un TypeError. Desafortunadamente, en realidad se concatenaráx
consigo mismocomp
veces. ¡Ups!x
es un vector, entonces debería tener un__rmul__
método (__rmul__ = __mul__
) de modo quecomp * x
debería escalarx
de la misma manera quex * comp
aparentemente se pretende.Tuve un problema similar al implementar una especie de clase vectorial. Una forma de verificar un número es convertirlo a uno, es decir, usando
Esto debería rechazar los casos en los que x no se puede convertir en un número; pero también puede rechazar otros tipos de estructuras de tipo numérico que podrían ser válidas, por ejemplo, números complejos.
fuente
Si desea llamar a diferentes métodos según el tipo de argumento, consulte
multipledispatch
.Desafortunadamente, (que yo sepa) no podemos escribir
@dispatch(Vector)
porque todavía estamos definiendo el tipoVector
, por lo que el nombre del tipo aún no está definido. En su lugar, estoy usando el tipo baselist
, que le permite incluso encontrar el producto escalar de aVector
y alist
.fuente
Manera corta y sencilla:
Salida:
Si el objeto es una cadena, se devolverá 'Falso':
Salida:
fuente
Tiene un elemento de datos, digamos
rec_day
que cuando se escribe en un archivo será unfloat
. Pero durante el procesamiento del programa puede serfloat
,int
ostr
tipo (str
se usa al inicializar un nuevo registro y contiene un valor de indicador ficticio).Luego puede verificar si tiene un número con este
Estructuré un programa de Python de esta manera y solo puse un 'parche de mantenimiento' usando esto como una verificación numérica. ¿Es la forma pitónica? Lo más probable es que no, ya que solía programar en COBOL.
fuente
Puede utilizar la función isdigit ().
fuente