Python: cómo identificar si una variable es una matriz o un escalar

Resuelto otmezger asked hace 11 años • 16 respuestas

Tengo una función que toma el argumento NBins. Quiero hacer una llamada a esta función con un escalar 50o una matriz [0, 10, 20, 30]. ¿Cómo puedo identificar dentro de la función cuál NBinses la longitud? o dicho de otra manera, ¿si es un escalar o un vector?

Probé esto:

>>> N=[2,3,5]
>>> P = 5
>>> len(N)
3
>>> len(P)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
>>> 

Como puede ver, no puedo aplicar lena P, ya que no es una matriz.... ¿Existe algo como isarrayo isscalaren Python?

gracias

otmezger avatar May 29 '13 13:05 otmezger
Aceptado
>>> import collections.abc
>>> isinstance([0, 10, 20, 30], collections.abc.Sequence)
True
>>> isinstance(50, collections.abc.Sequence)
False

nota : isinstancetambién admite una tupla de clases, type(x) in (..., ...)se debe evitar la verificación y es innecesaria.

Quizás también quieras comprobarnot isinstance(x, (str, unicode))

Como lo señaló @ 2080 y también aquí , esto no funcionará para numpymatrices. p.ej.

>>> import collections.abc
>>> import numpy as np
>>> isinstance((1, 2, 3), collections.abc.Sequence)
True
>>> isinstance(np.array([1, 2, 3]), collections.abc.Sequence)
False

En cuyo caso puedes probar la respuesta de @jpaddison3 :

>>> hasattr(np.array([1, 2, 3]), "__len__")
True
>>> hasattr([1, 2, 3], "__len__")
True
>>> hasattr((1, 2, 3), "__len__")
True

Sin embargo, como se indica aquí , esto tampoco es perfecto y clasificará incorrectamente (al menos según yo) los diccionarios como secuencias, mientras que isinstancewith collections.abc.Sequenceclasifica correctamente:

>>> hasattr({"a": 1}, "__len__")
True
>>> from numpy.distutils.misc_util import is_sequence
>>> is_sequence({"a": 1})
True
>>> isinstance({"a": 1}, collections.abc.Sequence)
False

Puede personalizar su solución con algo como esto y agregar más tipos isinstancesegún sus necesidades:

>>> isinstance(np.array([1, 2, 3]), (collections.abc.Sequence, np.ndarray))
True
>>> isinstance([1, 2, 3], (collections.abc.Sequence, np.ndarray))
True
jamylak avatar May 29 '2013 06:05 jamylak

Las respuestas anteriores suponen que la matriz es una lista estándar de Python. Como alguien que usa numpy con frecuencia, recomendaría una prueba muy pitónica de:

if hasattr(N, "__len__")
jpaddison3 avatar Nov 04 '2013 17:11 jpaddison3

Combinando las respuestas de @jamylak y @ jpaddison3, si necesita ser robusto contra matrices numerosas como entrada y manejarlas de la misma manera que las listas, debe usar

import numpy as np
isinstance(P, (list, tuple, np.ndarray))

Esto es robusto contra subclases de listas, tuplas y matrices numpy.

Y si también desea ser robusto frente a todas las demás subclases de secuencia (no solo lista y tupla), use

import collections
import numpy as np
isinstance(P, (collections.Sequence, np.ndarray))

¿Por qué debería hacer las cosas de esta manera isinstancey no compararlas type(P)con un valor objetivo? A continuación se muestra un ejemplo en el que creamos y estudiamos el comportamiento de NewListuna subclase trivial de lista.

>>> class NewList(list):
...     isThisAList = '???'
... 
>>> x = NewList([0,1])
>>> y = list([0,1])
>>> print x
[0, 1]
>>> print y
[0, 1]
>>> x==y
True
>>> type(x)
<class '__main__.NewList'>
>>> type(x) is list
False
>>> type(y) is list
True
>>> type(x).__name__
'NewList'
>>> isinstance(x, list)
True

A pesar xde ycompararlos como iguales, manejarlos typeresultaría en un comportamiento diferente. Sin embargo, dado que xes una instancia de una subclase de list, el uso isinstance(x,list)proporciona el comportamiento deseado y lo trata xde yla misma manera.

scottclowe avatar Mar 04 '2015 15:03 scottclowe

¿Existe un equivalente a isscalar() en numpy? Sí.

>>> np.isscalar(3.1)
True
>>> np.isscalar([3.1])
False
>>> np.isscalar(False)
True
>>> np.isscalar('abcd')
True
jmhl avatar Nov 13 '2015 04:11 jmhl