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?

Благодарность


person otmezger    schedule 29.05.2013    source источник
comment
Вы пробовали проверить это type?   -  person Sukrit Kalra    schedule 29.05.2013


Ответы (13)


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

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

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

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

person jamylak    schedule 29.05.2013
comment
спасибо, я не представлял, как инвертировать list, чтобы получить false для скаляров ... спасибо - person otmezger; 29.05.2013
comment
Хотя это отличный ответ, collections.Sequence также является азбукой для строки, так что это следует учитывать. Я использую что-то вроде if type(x) is not str and isinstance(x, collections.Sequence):. Это не здорово, но надежно. - person bbenne10; 04.08.2014
comment
@ bbenne10 конечно, но избегайте type, а также проверьте not isinstance(x, (str, unicode)) на Python 2 - person jamylak; 10.02.2015
comment
Почему вы сказали, что следует избегать проверки типа (x) в (..., ...)? Если вы так говорите, это было бы очень любезно объяснить, почему, возможно, я не единственный, кто задается вопросом, почему этого следует избегать. - person Olivier Pons; 30.05.2017
comment
@OlivierPons stackoverflow.com/questions / 1549801 / - person jamylak; 30.05.2017
comment
Ответ подходит для проверки массива, но не для проверки того, что переменная является скаляром, если отображение типа dict не считается скалярным, поскольку not isinstance({"a", 1, "b":3}, (list, collection.Sequence)) вернет true, что не означает, что переменная (здесь dict) является скаляром. - person Christian O'Reilly; 07.12.2019
comment
collections.Sequence - ›collections.abc.Sequence может быть требуется в Python 3.9 или 3.10. - person Bob Stein; 19.08.2020

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

if hasattr(N, "__len__")
person jpaddison3    schedule 04.11.2013
comment
строки имеют атрибут __len__ (так что я думаю, технически это не скалярный тип) - person xofer; 17.04.2014
comment
if hasattr(N, '__len__') and (not isinstance(N, str)) правильно учитывает строки. - person apdnu; 13.10.2014
comment
Также учитывайте dict на Python 3 - person Bruno Henrique; 24.01.2016

Объединяя ответы @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 таким же образом.

person scottclowe    schedule 04.03.2015
comment
Это ответ, который больше всего соответствовал моим потребностям. Я тоже только что добавил набор. Потому что я не хочу быть стойким против диктата. isinstance(P, (list, tuple, set, np.ndarray)) - person Santiago; 09.02.2020

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

>>> np.isscalar(3.1)
True
>>> np.isscalar([3.1])
False
>>> np.isscalar(False)
True
>>> np.isscalar('abcd')
True
person jmhl    schedule 13.11.2015
comment
Лучше бы и пример: >>> np.isscalar('abcd') возвращает True. - person Syrtis Major; 19.03.2016
comment
Благодарность! это гораздо более общий пример, чем любой из вышеперечисленных, и его следует предпочесть. Это также прямой ответ на вопрос ОП. - person Cristóbal Sifón; 24.06.2018
comment
Отлично. Хотя одна проблема заключается в том, что isscalar (None) возвращает False. Numpy реализует это как return (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number)) - person Shital Shah; 08.01.2019
comment
Нет, к сожалению. Функция numpy.isscalar() страдает рядом несовместимых конструктивных недостатков и, вероятно, будет не рекомендована к использованию в некоторых будущих версиях. Перефразируя официальную документацию: почти во всех случаях np.ndim(x) == 0 следует использовать вместо np.isscaler(x), так как первый также правильно вернет true для массивов 0d. Таким образом, надежной альтернативой numpy.isscalar() с прямой совместимостью было бы тривиальное обертывание numpy.ndim(): например, def is_scalar(obj): return np.ndim(obj) == 0 - person Cecil Curry; 28.02.2019
comment
На самом деле за это не следует голосовать, потому что np.isscalar сбивает с толку. Официальный документ предлагает использовать np.array.ndim везде, т.е. np.isscalar(np.array(12)) имеет значение False, хотя его следует рассматривать как скаляр, поскольку np.array(12).ndim равно 0. - person knh190; 04.06.2019
comment
Это не работает с сопоставлениями. np.ndim({'a':'b', 'c':'d'}) == 0 - person David Sauter; 07.11.2020

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

>>> N=[2,3,5]
>>> P = 5
>>> type(P) in (tuple, list)
False
>>> type(N) in (tuple, list)
True
person Sukrit Kalra    schedule 29.05.2013
comment
Было бы здорово, если бы человек, проголосовавший против ответа, тоже указал причину. - person Sukrit Kalra; 29.05.2013
comment
Я на самом деле проголосовал за, но потом понял, что он не работает в 2.7: ››› p = [] ››› тип (p) в (список) Traceback (последний звонок последний): File ‹stdin›, строка 1, в ‹module› - person Oleg Gryb; 12.06.2014
comment
@OlegGryb: Попробуйте type(p) in (list, ). - person Sukrit Kalra; 12.06.2014
comment
ах, это кортеж справа, а не список, понял, спасибо, теперь работает. Сожалею, что не могу проголосовать 2 раза - пока лучшее решение :) - person Oleg Gryb; 12.06.2014

Другой альтернативный подход (использование свойства 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

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

person Marek    schedule 29.05.2013

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

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

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

Итак, без лишних слов:

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

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

person Shital Shah    schedule 12.02.2019
comment
Это плохо работает со скалярными тензорами (TensorFlow), потому что у них есть метод len, но при попытке вызвать его на скалярном тензоре возникает ошибка: TypeError: Скалярный тензор не имеет len(). Вид раздражающего поведения со стороны TensorFlow ... - person Ben Farmer; 23.07.2020
comment
Чтобы справиться с этим, я сначала делаю что-то вроде if hasattr (obj, shape) и obj.shape == (), чтобы проверить эти случаи скалярных массивов. - person Ben Farmer; 23.07.2020

Просто используйте 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
person Mathieu Villion    schedule 12.04.2016
comment
NameError: имя 'size' не определено - person thang; 11.11.2016
comment
Это правда. Я использовал размер numpy, не замечая этого. Вам нужно: от размера импорта numpy - person Mathieu Villion; 04.12.2016
comment
np.size(5) и np.size([5]) оба == 1, поэтому это не позволяет правильно различать тип (т.е. идентифицировать скаляр), что, как я считаю, является целью. - person michael; 27.01.2017
comment
Это интересное замечание. Исходный вопрос относится к isscalar, который является функцией Matlab. В Matlab нет абсолютно никакой разницы между скаляром и массивом размера 1, будь то вектор или N-тусклый массив. ИМХО, это плюс для Матлаба. - person Mathieu Villion; 05.02.2017
comment
Безумие. Это означало бы {} == {{}}. - person John P; 14.05.2021

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

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

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

<type 'int'>

Так что вы можете различить, что это целое число или массив.

person unnati patil    schedule 29.05.2013

Я удивлен, что на такой базовый вопрос в Python, похоже, нет немедленного ответа. Мне кажется, что почти во всех предлагаемых ответах используется какая-то проверка типов, которая обычно не рекомендуется в 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
person Vincenzooo    schedule 29.08.2015
comment
Я также удивлен, что никто из них, кажется, тоже не имеет дела с генераторами. - person RhysC; 12.10.2016
comment
Он также не работает с сопоставлениями: >>> np.array({1:2, 3:4}).size == 1 - person David Sauter; 07.11.2020
comment
это потому, что функция np.array создает массив dtype object с единственным элементом, содержащим словарь (или генератор). Другое дело, когда np.array(list(a.items())).size или np.array(list(a.keys())).size дает другой результат. - person Vincenzooo; 08.11.2020

Чтобы ответить на вопрос в заголовке, прямой способ определить, является ли переменная скаляром, - это попытаться преобразовать ее в число с плавающей запятой. Если вы получите TypeError, это не так.

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
person Puck    schedule 18.04.2020
comment
Что-то не так с этим ответом? Выбранный ответ не выполняется при выполнении isinstance(np.arange(10), collections.Sequence). - person Stefano; 04.08.2020

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

person Sumanth Meenan    schedule 08.06.2019

Поскольку общее правило в Python состоит в том, чтобы просить прощения, а не разрешения, я думаю, что наиболее питонический способ обнаружить строку / скаляр из последовательности - это проверить, содержит ли он целое число:

try:
    1 in a
    print('{} is a sequence'.format(a))
except TypeError:
    print('{} is a scalar or string'.format(a))
person Nicola    schedule 07.09.2020