如何识别变量是数组还是标量

我有一个接受参数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,因为它不是一个数组....python中是否存在isarrayisscalar之类的东西?

谢谢

503608 次浏览
>>> import collections.abc
>>> isinstance([0, 10, 20, 30], collections.abc.Sequence)
True
>>> isinstance(50, collections.abc.Sequence)
False

请注意: isinstance也支持类的元组,检查type(x) in (..., ...)应该避免,是不必要的。

你可能还想检查not isinstance(x, (str, unicode))

正如@2080在这里所指出的,这将不适用于numpy数组。如。

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

在这种情况下,您可以尝试@jpaddison3中的答案:

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

然而,正如在这里所指出的那样,这也不是完美的,并且会错误地(至少在我看来)将字典分类为序列,而isinstancecollections.abc.Sequence则正确地分类:

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

你可以这样定制你的解决方案,根据你的需要在isinstance中添加更多类型:

>>> isinstance(np.array([1, 2, 3]), (collections.abc.Sequence, np.ndarray))
True
>>> isinstance([1, 2, 3], (collections.abc.Sequence, np.ndarray))
True

虽然@jamylak的方法更好,但这里有另一种方法

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

你可以检查变量的数据类型。

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

它会给你P的数据类型。

<type 'int'>

这样你就可以区分它是整数还是数组。

另一种替代方法(使用类的名字属性):

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


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


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


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

不需要进口任何东西。

前面的回答假设数组是python标准列表。作为一个经常使用numpy的人,我推荐一个非常python化的测试:

if hasattr(N, "__len__")

将@jamylak和@jpaddison3的答案结合在一起,如果需要健壮地将numpy数组作为输入,并以与列表相同的方式处理它们,则应该使用

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

这对于list, tuple和numpy数组的子类是健壮的。

如果您想对sequence的所有其他子类(不仅仅是list和tuple)也具有健壮性,请使用

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

为什么要这样处理isinstance,而不将type(P)与目标值进行比较?下面是一个例子,在这里我们创建并研究NewList的行为,它是list的一个普通子类。

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

尽管xy比较为相等,但通过type处理它们会导致不同的行为。然而,由于xlist的一个子类的实例,因此使用isinstance(x,list)可以得到所需的行为,并以相同的方式处理xy

我很惊讶,这样一个基本的问题在python中似乎没有一个直接的答案。 在我看来,几乎所有提出的答案都使用了某种类型 检查,在python中通常不建议这样做,它们似乎仅限于特定的情况(它们失败于不同的数值类型或非元组或列表的泛型可迭代对象)。< / p >

对我来说,更好的方法是导入numpy并使用array。尺寸,例如:

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

在numpy中是否有等效的isscalar() ?是的。

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

简单地使用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

这是我发现的最好的方法:检查__len____getitem__是否存在。

你可能会问为什么?原因包括:

  1. 流行的方法isinstance(obj, abc.Sequence)在一些对象上失败,包括PyTorch的张量,因为它们没有实现__contains__
  2. 不幸的是,Python的集合中什么都没有。abc,只检查__len____getitem__,我认为这是类数组对象的最小方法。
  3. 它适用于列表,元组,ndarray,张量等。

废话不多说:

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

请注意,我添加了默认参数,因为大多数时候您可能希望将字符串视为值,而不是数组。元组也是如此。

preds_test[0]的形状(128,128,1) 让我们使用isinstance()函数检查它的数据类型 Isinstance接受2个参数。 第一个参数是数据 第二个参数是数据类型 isinstance(preds_test[0], np.ndarray)输出为True。这意味着preds_test[0]是一个数组

要回答标题中的问题,判断变量是否是标量的直接方法是尝试将其转换为浮点数。如果你得到TypeError,它不是。

N = [1, 2, 3]
try:
float(N)
except TypeError:
print('it is not a scalar')
else:
print('it is a scalar')

由于Python中的一般准则是请求原谅而不是允许,我认为从序列中检测字符串/标量的最Python的方法是检查它是否包含整数:

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