为什么一个Numpy数组元素不是Python标量?

5

有人能解释一下Numpy的设计决策,为什么要将数组的单个元素与Python标量区分开来吗?

以下代码可以无错误运行

import numpy as np
a = np.array([1, 2, 3])
b = a[0]
print(b.size)

这说明b不是一个简单的Python标量,实际上type(b)返回的是numpy.int32而不是int
当然,如果定义b = 1,那么命令b.size将会抛出错误,因为

AttributeError: 'int' object has no attribute 'size'

我发现这种行为差异很令人困惑,想知道它的动机是什么。

这个问题很相关,可能是一个重复的问题:https://dev59.com/lXRA5IYBdhLWcg3w8ikl - Alex Riley
这份文档似乎声称,如果在许多科学计算环境中使用默认的Python功能,则会导致不正确的行为:http://docs.scipy.org/doc/numpy-1.10.0/reference/arrays.scalars.html - BlackVegetable
@ajcr 同样的答案可能适用于这个问题,但问题本身并没有让我觉得是重复的。 - BlackVegetable
1个回答

6

数组的元素和索引时得到的对象是不同的。

数组有一个数据缓冲区,它是由numpy的编译代码管理的字节块。每个元素可能由1个字节、4个字节、8个字节、16个字节等表示。

In [478]: A=np.array([1,2,3])

In [479]: A.__array_interface__
Out[479]: 
{'data': (167487856, False),
 'descr': [('', '<i4')],
 'shape': (3,),
 'strides': None,
 'typestr': '<i4',
 'version': 3}

将数据显示为字节列表(显示为字符):

In [480]: A.view('S1')
Out[480]: 
array(['\x01', '', '', '', '\x02', '', '', '', '\x03', '', '', ''], 
      dtype='|S1')

当你选择一个 A 元素时,会返回一个包含一个元素的数组(或类似的东西):
In [491]: b=A[0]

In [492]: b.shape
Out[492]: ()

In [493]: b.__array_interface__
Out[493]: 
{'__ref': array(1),
 'data': (167480104, False),
 'descr': [('', '<i4')],
 'shape': (),
 'strides': None,
 'typestr': '<i4',
 'version': 3}

type 不同,但是 b 具有与 A 相同的大部分属性,例如 shapestridesmean 等。

您必须使用 .item 访问基础“标量”:

In [496]: b.item()
Out[496]: 1

In [497]: type(b.item())
Out[497]: int

所以你可以将b视为一个具有numpy包装器的标量。对于b__array_interface__看起来非常像np.array(1)


非常感谢您清晰的回答。当然,这解释了区别的真正含义,但并没有解释为什么做出这个设计选择。这种区别仅仅是由于技术限制造成的吗?因为Numpy只是Python的一个包(不像MATLAB、Mathematica或IDL)?还是Numpy的选择比MATLAB更好,因为在MATLAB中不存在这种区别? - divenex
在Octave/MATLAB中,size(x(1))返回1,1。在原始的MATLAB中,所有东西都是2D矩阵;没有标量。但在新版本中这有所削弱。 - hpaulj
关键区别在于,在MATLAB中,size(1)size(x(1))是相同的:它们都返回1,1。单个数组元素与标量不可区分。但在Numpy中则不然。 - divenex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接