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

Posted

技术标签:

【中文标题】python:如何识别变量是数组还是标量【英文标题】:python: how to identify if a variable is an array or a scalar 【发布时间】:2013-05-24 07:22:44 【问题描述】:

我有一个接受参数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 的东西吗?

谢谢

【问题讨论】:

你试过测试它的type吗? 【参考方案1】:
>>> isinstance([0, 10, 20, 30], list)
True
>>> isinstance(50, list)
False

要支持任何类型的序列,请选中 collections.Sequence 而不是 list

注意isinstance 也支持类元组,检查type(x) in (..., ...) 应避免且没有必要。

您可能还想查看not isinstance(x, (str, unicode))

【讨论】:

谢谢,我没想到将 list 反转为标量为假...谢谢 虽然这是一个很好的答案,但 collections.Sequence 也是字符串的 ABC,因此应该考虑到这一点。我正在使用if type(x) is not str and isinstance(x, collections.Sequence): 之类的东西。这不是很好,但它是可靠的。 @bbenne10 当然可以,但要避免使用type,还要在 Python 2 上检查 not isinstance(x, (str, unicode)) 为什么说“检查类型(x) in (..., ...) 应该避免并且是不必要的。”?如果你这么说,那会很好地解释为什么,也许我不是唯一一个想知道为什么应该避免它的人。 collections.Sequence --> collections.abc.Sequence may 在 Python 3.9 或 3.10 中是必需的。【参考方案2】:

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

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

【讨论】:

如果投反对票的人也能给出理由,那就太好了。 我实际上已经投了赞成票,但后来意识到它在 2.7 中不起作用:>>> p=[] >>> type(p) in (list) Traceback(最近一次通话最后一次): 中的文件“”,第 1 行 @OlegGryb:试试type(p) in (list, ) 啊,右边是一个元组,不是列表,明白了,谢谢,现在可以使用了。我很遗憾,我不能投票两次 - 迄今为止最好的解决方案:)【参考方案3】:
>>> N=[2,3,5]
>>> P = 5
>>> type(P)==type(0)
True
>>> type([1,2])==type(N)
True
>>> type(P)==type([1,2])
False

【讨论】:

【参考方案4】:

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

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

它会给你输出 P 的数据类型。

<type 'int'>

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

【讨论】:

【参考方案5】:

另一种替代方法(使用类 name 属性):

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

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

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

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

无需导入任何东西。

【讨论】:

【参考方案6】:

以前的答案假定数组是 python 标准列表。作为一个经常使用 numpy 的人,我推荐一个非常 Python 的测试:

if hasattr(N, "__len__")

【讨论】:

字符串有一个__len__ 属性(所以我猜,在技术上不是标量类型) if hasattr(N, '__len__') and (not isinstance(N, str)) 会正确考虑字符串。 在 Python 3 上也考虑到 dict【参考方案7】:

将@jamylak 和@jpaddison3 的答案结合在一起,如果您需要对 numpy 数组作为输入具有鲁棒性并以与列表相同的方式处理它们,您应该使用

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

这对于列表、元组和 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

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

【讨论】:

这是最适合我需要的答案。我也刚刚添加了设置。因为我不想对听写强硬。 isinstance(P, (list, tuple, set, np.ndarray))【参考方案8】:

我很惊讶这样一个基本问题在 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

【讨论】:

我也很惊讶它们似乎都没有处理生成器。 它也不适用于映射:&gt;&gt;&gt; np.array(1:2, 3:4).size == 1 这些是因为 np.array 函数创建了一个 dtype object 的数组,其中一个元素包含字典(或生成器)。使用np.array(list(a.items())).sizenp.array(list(a.keys())).size 会产生不同的结果。【参考方案9】:

numpy 中是否有等效于 isscalar() 的方法?是的。

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

【讨论】:

这样会更好,还有一个例子:&gt;&gt;&gt; np.isscalar('abcd') 返回True 谢谢!这是一个比上述任何一个都更普遍的例子,应该是首选。这也是对 OP 问题的直接回答。 不错。尽管一个问题是 isscalar(None) 返回 False。 Numpy 将其实现为 return (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number)) 不,很遗憾。numpy.isscalar() 函数存在许多不可调和的设计缺陷,并且可能在未来的某个版本中会被弃用。套用official documentation:“在几乎所有情况下,都应该使用np.ndim(x) == 0 而不是np.isscaler(x),因为前者也将正确地为0d 数组返回true。”因此,numpy.isscalar() 的强大前向兼容替代方案是简单地包装 numpy.ndim():例如,def is_scalar(obj): return np.ndim(obj) == 0 实际上这不应该被赞成,因为np.isscalar 令人困惑。官方文档建议在任何地方使用np.array.ndim,即np.isscalar(np.array(12)) 为False,而它应被视为标量,因为np.array(12).ndim 为0。【参考方案10】:

只需使用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

【讨论】:

NameError: name 'size' is not defined 确实如此。我正在使用 numpy 大小而没有注意到它。你需要:从 numpy 导入大小 np.size(5)np.size([5]) 都是 == 1,所以这不能正确区分类型(即识别标量),我认为这是目标。 这是一个有趣的评论。原始问题是指 isscalar,它是一个 Matlab 函数。在 Matlab 中,标量和大小为 1 的数组之间绝对没有区别,可以是向量或 N-dim 数组。恕我直言,这是 Matlab 的一个优点。 疯狂。这意味着 == 【参考方案11】:

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

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

    流行的方法 isinstance(obj, abc.Sequence) 在某些对象(包括 PyTorch 的张量)上失败,因为它们没有实现 __contains__。 不幸的是,Python 的 collections.abc 中没有任何内容只检查 __len____getitem__,我认为它们是类数组对象的最小方法。 它适用于列表、元组、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

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

【讨论】:

这不适用于标量 (TensorFlow) 张量,因为它们有一个 len 方法,但如果您尝试在标量张量上调用它会引发错误:TypeError :标量张量没有len()。 TensorFlow 的一些令人讨厌的行为...... 为了解决这个问题,我发现自己首先要执行 if hasattr(obj,"shape") 和 obj.shape==() 之类的操作来检查这些“标量数组”情况。【参考方案12】:

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

【讨论】:

【参考方案13】:

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

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

【讨论】:

这个答案有什么问题吗?执行isinstance(np.arange(10), collections.Sequence) 时选择的答案失败。【参考方案14】:

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

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

【讨论】:

以上是关于python:如何识别变量是数组还是标量的主要内容,如果未能解决你的问题,请参考以下文章

perl 第五弹 变量 I

如何在python中强制标量的类型

如何在 Python 中调试“IndexError:标量变量的无效索引”错误?

与标量变量相反

如何检查变量是 python 列表、numpy 数组还是 pandas 系列

perl 第六弹 变量 II