Dado un objeto de Python arbitrario, ¿cuál es la mejor manera de determinar si es un número? Aquí isse 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, booles 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) != boolQuieres 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
isinstancecon números . Número : una clase base abstracta (ABC) que existe exactamente para este propósito (existen muchos más ABC en elcollectionsmó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
0y 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únunregistermétodo [[por ejemplo, puede hacer su propio ABCWeirdNumy registrar allí todos los tipos extraños para usted, luego primero verifiqueisinstanceque estén disponibles antes de continuar a la comprobaciónisinstancede lo normalnumbers.Numberpara continuar con éxito.Por cierto, siempre que necesite verificar si
xpuede 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, aZeroDivisionErroroValueError& 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
TypeErrorde 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
isinstancepuede 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.Sequencey 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 == 0intpor 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
fooprimero: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.isnanProbablemente 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
ves un vector y lo multiplicamos porx. Si tiene sentido multiplicar cada componente devporx, 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
xes un vector, entonces se[comp * x for comp in self]obtendrá el producto externo dexanv. Este es un tensor de rango 2, no un escalar.comp*xva a escalarxporcomp, estaba asumiendo que plantearía un TypeError. Desafortunadamente, en realidad se concatenaráxconsigo mismocompveces. ¡Ups!xes un vector, entonces debería tener un__rmul__método (__rmul__ = __mul__) de modo quecomp * xdebería escalarxde la misma manera quex * compaparentemente 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 aVectory 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_dayque cuando se escribe en un archivo será unfloat. Pero durante el procesamiento del programa puede serfloat,intostrtipo (strse 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