ChatGPT解决这个技术问题 Extra ChatGPT

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,因为它不是数组.... python 中有类似 isarrayisscalar 的东西吗?

谢谢

您是否尝试过测试它的 type

j
jamylak
>>> 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))

正如 @2080here 所指出的,这不适用于 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

但是,如 here 所述,这也不是完美的,并且会错误地(至少在我看来)将字典分类为序列,而带有 collections.abc.Sequenceisinstance 会正确分类:

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

谢谢,我没想到将 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 中是必需的。
j
jpaddison3

以前的答案假设该数组是一个 python 标准列表。作为经常使用 numpy 的人,我建议对以下内容进行非常 Python 的测试:

if hasattr(N, "__len__")

字符串有一个 __len__ 属性(所以我猜,技术上不是标量类型)
if hasattr(N, '__len__') and (not isinstance(N, str)) 将正确考虑字符串。
还要考虑 Python 3 上的 dict
s
scottclowe

将@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 的行为,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))
S
Stefan

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

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

最好还有一个例子:>>> 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。
S
Sukrit Kalra

虽然@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 (最近一次调用最后一次): File "" ,第 1 行,在 <模块>
@OlegGryb:试试 type(p) in (list, )
啊,它是右边的一个元组,而不是一个列表,明白了,谢谢,它现在可以工作了。我很遗憾,我不能投票两次 - 迄今为止最好的解决方案:)
M
Marek

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

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

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

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

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

无需导入任何东西。


S
Shital Shah

这是我发现的最佳方法:检查 __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: Scalar tensor has no len() . TensorFlow 的一些令人讨厌的行为......
为了解决这个问题,我发现自己首先要做一些类似 if hasattr(obj,"shape") 和 obj.shape==() 的事情来检查这些“标量数组”的情况。
s
suhailvs
>>> N=[2,3,5]
>>> P = 5
>>> type(P)==type(0)
True
>>> type([1,2])==type(N)
True
>>> type(P)==type([1,2])
False

P
Puck

要回答标题中的问题,判断变量是否为标量的直接方法是尝试将其转换为浮点数。如果您得到 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) 时选择的答案失败。
u
unnati patil

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

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

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

<type 'int'>

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


V
Vincenzooo

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

我也很惊讶他们似乎也没有处理发电机。
它也不适用于映射:>>> np.array({1:2, 3:4}).size == 1
这是因为 np.array 函数创建了一个 dtype object 的数组,其中一个元素包含字典(或生成器)。使用 np.array(list(a.items())).sizenp.array(list(a.keys())).size 会产生不同的结果。
M
Mathieu Villion

只需使用 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:名称“大小”未定义
确实如此。我正在使用 numpy 大小而没有注意到它。您需要:从 numpy 导入大小
np.size(5)np.size([5]) 都是 == 1,所以这不能正确区分类型(即识别标量),我认为这是目标。
这是一个有趣的评论。原始问题是指 isscalar,它是一个 Matlab 函数。在 Matlab 中,标量和大小为 1 的数组之间绝对没有区别,可以是向量或 N-dim 数组。恕我直言,这是 Matlab 的一个优点。
疯狂。这意味着 {} == {{}}
N
Nicola

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

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

S
Sumanth Meenan

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