在 numpy 中,许多对象的构造函数接受“array_like”作为第一个参数。是否有这样的对象的定义,无论是作为抽象元类,还是应该包含方法的文档??
事实证明,从技术上讲,几乎所有东西都是类似数组的。 “类似数组”更多的是关于如何解释输入的声明,而不是对输入内容的限制;如果参数被记录为类似数组,NumPy 将尝试将其解释为数组。
除了几乎同义反复的定义之外,没有类似数组的正式定义——类数组是np.array
可以转换为
ndarray
的任何Python对象。要超越这一点,您需要研究源代码。
NPY_NO_EXPORT PyObject *
PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
int max_depth, int flags, PyObject *context)
{
/*
* This is the main code to make a NumPy array from a Python
* Object. It is called from many different places.
*/
PyArrayObject *arr = NULL, *ret;
PyArray_Descr *dtype = NULL;
int ndim = 0;
npy_intp dims[NPY_MAXDIMS];
/* Get either the array or its parameters if it isn't an array */
if (PyArray_GetArrayParamsFromObject(op, newtype,
0, &dtype,
&ndim, dims, &arr, context) < 0) {
Py_XDECREF(newtype);
return NULL;
}
...
特别有趣的是PyArray_GetArrayParamsFromObject
np.array
期望的对象类型:
NPY_NO_EXPORT int
PyArray_GetArrayParamsFromObject(PyObject *op,
PyArray_Descr *requested_dtype,
npy_bool writeable,
PyArray_Descr **out_dtype,
int *out_ndim, npy_intp *out_dims,
PyArrayObject **out_arr, PyObject *context)
{
PyObject *tmp;
/* If op is an array */
/* If op is a NumPy scalar */
/* If op is a Python scalar */
/* If op supports the PEP 3118 buffer interface */
/* If op supports the __array_struct__ or __array_interface__ interface */
/*
* If op supplies the __array__ function.
* The documentation says this should produce a copy, so
* we skip this method if writeable is true, because the intent
* of writeable is to modify the operand.
* XXX: If the implementation is wrong, and/or if actual
* usage requires this behave differently,
* this should be changed!
*/
/* Try to treat op as a list of lists */
/* Anything can be viewed as an object, unless it needs to be writeable */
}
所以通过研究源码我们可以得出类似数组的结论
__array_struct__
或
__array_interface__
接口或 的对象
__array__
函数的任何对象,或
object
dtype 的 0 维数组。
NumPy 1.21 引入 numpy.typing.ArrayLike
commit中最初定义如下:
class _SupportsArray(Protocol):
@overload
def __array__(self, __dtype: DtypeLike = ...) -> ndarray: ...
@overload
def __array__(self, dtype: DtypeLike = ...) -> ndarray: ...
ArrayLike = Union[bool, int, float, complex, _SupportsArray, Sequence]
但是,可以在 ArrayLike
中找到 numpy/_typing/_array_like.py
的最新定义:
_ArrayLike = Union[
_NestedSequence[_SupportsArray[_DType]],
_NestedSequence[_T],
]
ArrayLike = Union[
_RecursiveSequence,
_ArrayLike[
"dtype[Any]",
Union[bool, int, float, complex, str, bytes]
],
]
“类似数组” 在 NumPy 中使用,指的是可以作为第一个参数传递给 numpy.array()
以创建数组 () 的任何内容。根据
Numpy 文档:
一般来说,Python 中以类似数组结构排列的数值数据可以通过使用 array() 函数转换为数组。最明显的例子是列表和元组。有关其使用的详细信息,请参阅 array() 的文档。某些对象可能支持数组协议并允许以这种方式转换为数组。确定是否可以使用 array() 将对象转换为 numpy 数组的一个简单方法就是以交互方式尝试它,看看它是否有效! (Python 方式)。欲了解更多信息,请阅读:
iterable
与
array_like
概念,除了其他答案中提到的用户指南部分中的解释之外,还有一个官方声明(在Numpy术语表中):
因此甚至可以考虑标量,就像
array_like
任何可以解释为 ndarray 的序列。这包括 嵌套列表、元组、标量和现有数组。
np.array(1024)
一样。
事实证明,“类数组”的概念不再是抽象基类或协议,而是更多地涉及如何处理各种对象的类数组。也就是说,类数组是关于当对象作为类数组参数提供时将如何处理该对象的语句。但几乎任何对象都可以作为类似数组的参数提供。
对于许多对象来说,类似数组的处理方式与可迭代对象的处理方式大致相同。对于序列对象来说也是如此:
>>> x=[1,2,3]
>>> a = np.array(x)
>>> a[0]
1
但是,numpy 通常不会以相同的方式处理可迭代对象(当作为类似数组的参数提供时)。相反,它将类似数组的对象视为嵌套对象或原子对象,具体取决于类型。这里有一些可迭代对象的示例(这个想法听起来与类似数组密切相关,但完全不同),但 numpy 将其视为原子。
str
对象)
array()
工厂将所有这些视为原子(即非嵌套)值。简而言之:类数组绝不是
typing.Iterable
的同义词。