Python: как определить, является ли переменная массивом или скалярным

У меня есть функция, которая принимает аргумент NBins. Я хочу сделать вызов этой функции со скалярным 50 или массивом [0, 10, 20, 30]. Как я могу идентифицировать внутри функции, какова длина NBins? или иначе, если это скаляр или вектор?

Я пробовал это:

>>> 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()
>>> 

Как вы видите, я не могу применить len к P, так как это не массив.... Есть ли что-то вроде isarray или isscalar в python?

спасибо

Ответ 1

>>> isinstance([0, 10, 20, 30], list)
True
>>> isinstance(50, list)
False

Чтобы поддерживать любой тип последовательности, проверьте collections.Sequence вместо list.

note: isinstance также поддерживает кортеж классов, проверить type(x) in (..., ...) следует избегать и не нужно.

Вы также можете проверить not isinstance(x, (str, unicode))

Ответ 2

Предыдущие ответы предполагают, что массив является стандартным списком python. Поскольку кто-то часто использует numpy, я бы рекомендовал очень pythonic тест:

if hasattr(N, "__len__")

Ответ 3

Объединение @jamylak и @jpaddison3 отвечает вместе, если вам нужно быть устойчивым к массивам numpy в качестве ввода и обрабатывать их так же, как списки, вы должны использовать

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

Это устойчиво против подклассов массивов list, tuple и numpy.

И если вы хотите быть надежным против всех других подклассов последовательности (а не только список и кортеж), используйте

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

Зачем вам это делать с isinstance и не сравнивать type(P) с целевым значением? Вот пример, где мы делаем и изучаем поведение NewList, тривиального подкласса списка.

>>> 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

Несмотря на то, что x и y сравниваются как равные, обработка их с помощью type приведет к поведению. Однако, поскольку x является экземпляром подкласса list, использование isinstance(x,list) дает желаемое поведение и обрабатывает x и y тем же способом.

Ответ 4

Есть ли эквивалент isscalar() в numpy? Да.

>>> np.isscalar(3.1)
True
>>> np.isscalar([3.1])
False
>>> np.isscalar(False)
True

Ответ 5

В то время как подход @jamylak является лучшим, вот альтернативный подход

>>> N=[2,3,5]
>>> P = 5
>>> type(P) in (tuple, list)
False
>>> type(N) in (tuple, list)
True

Ответ 6

Другой альтернативный подход (использование свойства class name):

N = [2,3,5]
P = 5

type(N).__name__ == 'list'
True

type(P).__name__ == 'int'
True

type(N).__name__ in ('list', 'tuple')
True

Не нужно ничего импортировать.

Ответ 7

Просто используйте size вместо len!

>>> from numpy import size
>>> N = [2, 3, 5]
>>> size(N)
3
>>> N = array([2, 3, 5])
>>> size(N)
3
>>> P = 5
>>> size(P)
1

Ответ 8

>>> N=[2,3,5]
>>> P = 5
>>> type(P)==type(0)
True
>>> type([1,2])==type(N)
True
>>> type(P)==type([1,2])
False

Ответ 9

Вы можете проверить тип данных переменной.

N = [2,3,5]
P = 5
type(P)

Он выдаст вам значение типа данных P.

<type 'int'>

Чтобы вы могли отличить это, это целое число или массив.

Ответ 10

Я удивлен, что такой базовый вопрос, похоже, не имеет прямого ответа на питоне. Мне кажется, что почти все предложенные ответы используют какой-то тип проверка, которая обычно не рекомендуется в python, и они, по-видимому, ограничены конкретным случаем (они терпят неудачу с разными численными типами или универсальными итерационными объектами, которые не являются кортежами или списками).

Для меня лучше работает импорт numpy и использование array.size, например:

>>> a=1
>>> np.array(a)
Out[1]: array(1)

>>> np.array(a).size
Out[2]: 1

>>> np.array([1,2]).size
Out[3]: 2

>>> np.array('125')
Out[4]: 1

Примечание:

>>> len(np.array([1,2]))

Out[5]: 2

а

>>> len(np.array(a))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-40-f5055b93f729> in <module>()
----> 1 len(np.array(a))

TypeError: len() of unsized object

Ответ 11

Вот лучший подход, который я нашел: Проверьте существование __len__ и __getitem__.

Вы можете спросить почему? Причины включают в себя:

  1. Это обнаруживает несколько популярных объектов, которые в действительности являются массивами, включая собственный список Python и кортеж, NumPy ndarray и PyTorch Tensor.
  2. Другой популярный метод isinstance(obj, abc.Sequence) не работает на некоторых объектах, включая PyTorch Tensor, потому что они не реализуют __contains__.
  3. Использование collection.abc гораздо предпочтительнее, но, к сожалению, в Python collection.abc нет ничего, что проверяло бы только __len__ и __getitem__.

Так что без лишних слов:

def is_array_like(obj, string_is_array=False, tuple_is_array=True):
    result = hasattr(obj, "__len__") and hasattr(obj, '__getitem__') 
    if result and not string_is_array and isinstance(obj, (str, abc.ByteString)):
        result = False
    if result and not tuple_is_array and isinstance(obj, tuple):
        result = False
    return result

Обратите внимание, что я добавил параметры по умолчанию, потому что большую часть времени вы можете рассматривать строки как значения, а не как массивы. Аналогично для кортежей.

Ответ 12

preds_test [0] имеет форму (128,128,1). Давайте проверим тип данных с помощью функции isinstance(). isinstance принимает 2 аргумента. 1-й аргумент - это данные. 2-й аргумент - это тип данных isinstance (preds_test [0], np.ndarray). Это означает, что preds_test [0] является массивом.