NumPy-源码解析-五十一-

55 阅读1小时+

NumPy 源码解析(五十一)

.\numpy\numpy\_core\numeric.py

# 导入 functools 模块,用于支持创建偏函数
import functools
# 导入 itertools 模块,用于高效的迭代器循环
import itertools
# 导入 operator 模块,用于函数操作符的函数
import operator
# 导入 sys 模块,提供对解释器相关的功能访问
import sys
# 导入 warnings 模块,用于警告控制
import warnings
# 导入 numbers 模块,提供数值抽象基类
import numbers
# 导入 builtins 模块,提供内置函数的访问
import builtins
# 导入 math 模块,提供基本的数学函数
import math

# 导入 numpy 库,并重命名为 np
import numpy as np
# 从当前包中导入 multiarray 模块
from . import multiarray
# 从当前包中导入 numerictypes 模块,并重命名为 nt
from . import numerictypes as nt
# 从 multiarray 模块中导入指定的函数和常量
from .multiarray import (
    ALLOW_THREADS, BUFSIZE, CLIP, MAXDIMS, MAY_SHARE_BOUNDS, MAY_SHARE_EXACT,
    RAISE, WRAP, arange, array, asarray, asanyarray, ascontiguousarray,
    asfortranarray, broadcast, can_cast, concatenate, copyto, dot, dtype,
    empty, empty_like, flatiter, frombuffer, from_dlpack, fromfile, fromiter,
    fromstring, inner, lexsort, matmul, may_share_memory, min_scalar_type,
    ndarray, nditer, nested_iters, promote_types, putmask, result_type,
    shares_memory, vdot, where, zeros, normalize_axis_index,
    _get_promotion_state, _set_promotion_state, vecdot
)
# 从当前包中导入 overrides 模块
from . import overrides
# 从当前包中导入 umath 模块
from . import umath
# 从当前包中导入 shape_base 模块
from . import shape_base
# 从 overrides 模块中导入指定的函数
from .overrides import set_array_function_like_doc, set_module
# 从 umath 模块中导入指定的函数和常量
from .umath import (multiply, invert, sin, PINF, NAN)
# 从 numerictypes 模块中导入全部内容
from . import numerictypes
# 从 ..exceptions 包中导入 AxisError 异常类
from ..exceptions import AxisError
# 从当前包中导入 _ufunc_config 模块,导入 errstate 和 _no_nep50_warning 两个对象
from ._ufunc_config import errstate, _no_nep50_warning

# 将 invert 函数重命名为 bitwise_not
bitwise_not = invert
# 获取 sin 函数的类型,并将结果赋值给 ufunc
ufunc = type(sin)
# 将 newaxis 设置为 None
newaxis = None

# 使用 functools.partial 创建 array_function_dispatch 函数,其中 module 参数设置为 'numpy'
array_function_dispatch = functools.partial(
    overrides.array_function_dispatch, module='numpy')

# __all__ 列表定义了模块中所有需要导出的公共接口
__all__ = [
    'newaxis', 'ndarray', 'flatiter', 'nditer', 'nested_iters', 'ufunc',
    'arange', 'array', 'asarray', 'asanyarray', 'ascontiguousarray',
    'asfortranarray', 'zeros', 'count_nonzero', 'empty', 'broadcast', 'dtype',
    'fromstring', 'fromfile', 'frombuffer', 'from_dlpack', 'where',
    'argwhere', 'copyto', 'concatenate', 'lexsort', 'astype',
    'can_cast', 'promote_types', 'min_scalar_type',
    'result_type', 'isfortran', 'empty_like', 'zeros_like', 'ones_like',
    'correlate', 'convolve', 'inner', 'dot', 'outer', 'vdot', 'roll',
    'rollaxis', 'moveaxis', 'cross', 'tensordot', 'little_endian',
    'fromiter', 'array_equal', 'array_equiv', 'indices', 'fromfunction',
    'isclose', 'isscalar', 'binary_repr', 'base_repr', 'ones',
    'identity', 'allclose', 'putmask',
    'flatnonzero', 'inf', 'nan', 'False_', 'True_', 'bitwise_not',
    'full', 'full_like', 'matmul', 'vecdot', 'shares_memory',
    'may_share_memory', '_get_promotion_state', '_set_promotion_state']

# 定义 _zeros_like_dispatcher 函数,用于 zeros_like 函数的分派器
def _zeros_like_dispatcher(
    a, dtype=None, order=None, subok=None, shape=None, *, device=None
):
    # 返回参数 a 的元组形式
    return (a,)

# 使用 array_function_dispatch 装饰器注册 _zeros_like_dispatcher 函数
@array_function_dispatch(_zeros_like_dispatcher)
# 定义 zeros_like 函数,返回一个与给定数组 a 相同形状和类型的全零数组
def zeros_like(
    a, dtype=None, order='K', subok=True, shape=None, *, device=None
):
    """
    Return an array of zeros with the same shape and type as a given array.

    Parameters
    ----------
    a : array_like
        The shape and data-type of `a` define these same attributes of
        the returned array.
    dtype : data-type, optional
        Overrides the data type of the result.

        .. versionadded:: 1.6.0
    """
    # 函数文档字符串,描述了函数的功能和参数信息
    res = empty_like(
        a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
    )
    # 使用 `empty_like` 函数创建一个与输入数组 `a` 相同形状和类型的全零数组 `res`。
    # 可选参数 `dtype` 指定数组的数据类型,`order` 指定数组的存储顺序,`subok` 指定是否使用子类类型。
    # `shape` 参数可以覆盖结果数组的形状,如果 `order='K'` 且维度数不变,则尝试保持存储顺序,否则默认为 'C'。
    # `device` 参数指定创建数组的设备,仅用于 Array-API 兼容性,如果传递了此参数,必须为 `"cpu"`。

    # needed instead of a 0 to get same result as zeros for string dtypes
    # 为了在处理字符串类型数据时获得与 `zeros` 函数相同的结果,需要使用 `zeros(1, dtype=res.dtype)`。
    z = zeros(1, dtype=res.dtype)
    # 创建一个与 `res` 相同数据类型的长度为 1 的全零数组 `z`。

    multiarray.copyto(res, z, casting='unsafe')
    # 将 `z` 的值复制到 `res`,允许不安全类型转换。

    return res
    # 返回结果数组 `res`。
# 将该函数标记为数组函数,以便于文档生成器生成相应的文档
@set_array_function_like_doc
# 将该函数的模块标记为 'numpy',这样文档生成器可以正确归类和组织文档
@set_module('numpy')
# 定义一个创建指定形状和类型、填充为全1的新数组的函数
def ones(shape, dtype=None, order='C', *, device=None, like=None):
    """
    Return a new array of given shape and type, filled with ones.

    Parameters
    ----------
    shape : int or sequence of ints
        Shape of the new array, e.g., ``(2, 3)`` or ``2``.
    dtype : data-type, optional
        The desired data-type for the array, e.g., `numpy.int8`.  Default is
        `numpy.float64`.
    order : {'C', 'F'}, optional, default: C
        Whether to store multi-dimensional data in row-major
        (C-style) or column-major (Fortran-style) order in
        memory.
    device : str, optional
        The device on which to place the created array. Default: None.
        For Array-API interoperability only, so must be ``"cpu"`` if passed.

        .. versionadded:: 2.0.0
    ${ARRAY_FUNCTION_LIKE}

        .. versionadded:: 1.20.0

    Returns
    -------
    out : ndarray
        Array of ones with the given shape, dtype, and order.

    See Also
    --------
    ones_like : Return an array of ones with shape and type of input.
    empty : Return a new uninitialized array.
    zeros : Return a new array setting values to zero.
    full : Return a new array of given shape filled with value.

    Examples
    --------
    >>> np.ones(5)
    array([1., 1., 1., 1., 1.])

    >>> np.ones((5,), dtype=int)
    array([1, 1, 1, 1, 1])

    >>> np.ones((2, 1))
    array([[1.],
           [1.]])

    >>> s = (2,2)
    >>> np.ones(s)
    array([[1.,  1.],
           [1.,  1.]])

    """
    # 如果传入了 like 参数,则调用 _ones_with_like 函数,创建与 like 参数形状、类型一致的全1数组
    if like is not None:
        return _ones_with_like(
            like, shape, dtype=dtype, order=order, device=device
        )

    # 否则,创建一个空的数组 a,形状和类型由 shape 和 dtype 决定,顺序由 order 决定
    a = empty(shape, dtype, order, device=device)
    # 将数组 a 中所有元素的值设置为 1,这里使用 'unsafe' 模式进行强制类型转换
    multiarray.copyto(a, 1, casting='unsafe')
    # 返回填充为全1的数组 a
    return a


# 将 _ones_with_like 函数与 ones 函数关联,使得 _ones_with_like 能够根据数组函数分派机制被调用
_ones_with_like = array_function_dispatch()(ones)


# 定义 _ones_like_dispatcher 函数,用于根据参数分派给 ones_like 函数
def _ones_like_dispatcher(
    a, dtype=None, order=None, subok=None, shape=None, *, device=None
):
    return (a,)


# 使用 _ones_like_dispatcher 函数注册 ones_like 函数,使其能够根据数组函数分派机制被调用
@array_function_dispatch(_ones_like_dispatcher)
# 定义 ones_like 函数,返回一个与给定数组 a 形状和类型相同的全1数组
def ones_like(
    a, dtype=None, order='K', subok=True, shape=None, *, device=None
):
    """
    Return an array of ones with the same shape and type as a given array.

    Parameters
    ----------
    a : array_like
        The shape and data-type of `a` define these same attributes of
        the returned array.
    dtype : data-type, optional
        Overrides the data type of the result.

        .. versionadded:: 1.6.0
    order : {'C', 'F', 'A', or 'K'}, optional
        Overrides the memory layout of the result. 'C' means C-order,
        'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous,
        'C' otherwise. 'K' means match the layout of `a` as closely
        as possible.

        .. versionadded:: 1.6.0
    subok : bool, optional.
        If True, then the newly created array will use the sub-class
        type of `a`, otherwise it will be a base-class array. Defaults
        to True.
    """
    pass
    # shape参数用于指定返回数组的形状,可以是整数或整数序列,可选项。
    # 如果指定了shape,则覆盖结果数组的形状。如果order='K'并且维度未改变,则尝试保持顺序;否则,隐含使用order='C'。
    # device参数用于指定创建数组时使用的设备,默认为None。仅用于Array-API互操作性,如果传递了值,必须为"cpu"。
    # 返回值
    # -------
    # out : ndarray
    #     与输入数组`a`具有相同形状和类型的全1数组。
    #
    # 参见
    # --------
    # empty_like : 返回一个形状和类型与输入相同的空数组。
    # zeros_like : 返回一个形状和类型与输入相同的全0数组。
    # full_like : 返回一个形状与输入相同且填充了特定值的新数组。
    # ones : 返回一个设置值为1的新数组。
    #
    # 示例
    # --------
    # >>> x = np.arange(6)
    # >>> x = x.reshape((2, 3))
    # >>> x
    # array([[0, 1, 2],
    #        [3, 4, 5]])
    # >>> np.ones_like(x)
    # array([[1, 1, 1],
    #        [1, 1, 1]])
    #
    # >>> y = np.arange(3, dtype=float)
    # >>> y
    # array([0., 1., 2.])
    # >>> np.ones_like(y)
    # array([1.,  1.,  1.])
    """
    res = empty_like(
        a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
    )
    # 将值1复制到res数组中,使用'unsafe'转换方式
    multiarray.copyto(res, 1, casting='unsafe')
    # 返回生成的数组res
    return res
# 定义一个函数 `_full_dispatcher`,用于创建包含指定元素的数组,返回值是一个元组
def _full_dispatcher(
    shape, fill_value, dtype=None, order=None, *, device=None, like=None
):
    return(like,)


# 修饰器,设置函数的行为类似于某个函数文档
@set_array_function_like_doc
# 设置函数所属的模块为 'numpy'
@set_module('numpy')
# 定义函数 `full`,返回一个指定形状和类型的新数组,用指定值填充
def full(shape, fill_value, dtype=None, order='C', *, device=None, like=None):
    """
    Return a new array of given shape and type, filled with `fill_value`.

    Parameters
    ----------
    shape : int or sequence of ints
        Shape of the new array, e.g., ``(2, 3)`` or ``2``.
    fill_value : scalar or array_like
        Fill value.
    dtype : data-type, optional
        The desired data-type for the array  The default, None, means
         ``np.array(fill_value).dtype``.
    order : {'C', 'F'}, optional
        Whether to store multidimensional data in C- or Fortran-contiguous
        (row- or column-wise) order in memory.
    device : str, optional
        The device on which to place the created array. Default: None.
        For Array-API interoperability only, so must be ``"cpu"`` if passed.

        .. versionadded:: 2.0.0
    ${ARRAY_FUNCTION_LIKE}

        .. versionadded:: 1.20.0

    Returns
    -------
    out : ndarray
        Array of `fill_value` with the given shape, dtype, and order.

    See Also
    --------
    full_like : Return a new array with shape of input filled with value.
    empty : Return a new uninitialized array.
    ones : Return a new array setting values to one.
    zeros : Return a new array setting values to zero.

    Examples
    --------
    >>> np.full((2, 2), np.inf)
    array([[inf, inf],
           [inf, inf]])
    >>> np.full((2, 2), 10)
    array([[10, 10],
           [10, 10]])

    >>> np.full((2, 2), [1, 2])
    array([[1, 2],
           [1, 2]])

    """
    # 如果指定了 `like` 参数,则返回根据 `like` 的形状和类型创建的新数组
    if like is not None:
        return _full_with_like(
            like, shape, fill_value, dtype=dtype, order=order, device=device
        )

    # 如果未指定 `dtype`,将 `fill_value` 转换成数组并获取其数据类型
    if dtype is None:
        fill_value = asarray(fill_value)
        dtype = fill_value.dtype
    # 创建一个未初始化的数组 `a`,指定形状、数据类型、存储顺序和设备
    a = empty(shape, dtype, order, device=device)
    # 将 `fill_value` 的值复制到数组 `a` 中
    multiarray.copyto(a, fill_value, casting='unsafe')
    return a


# 使用函数分发装饰器注册 `full` 函数
_full_with_like = array_function_dispatch()(full)


# 定义一个函数 `_full_like_dispatcher`,用于返回一个元组,指定其参数 `a`
def _full_like_dispatcher(
    a, fill_value, dtype=None, order=None, subok=None, shape=None,
    *, device=None
):
    return (a,)


# 使用函数分发装饰器注册 `full_like` 函数,并指定 `_full_like_dispatcher` 作为分发函数
@array_function_dispatch(_full_like_dispatcher)
# 定义函数 `full_like`,返回一个与给定数组 `a` 相同形状和类型的新数组,用指定值填充
def full_like(
    a, fill_value, dtype=None, order='K', subok=True, shape=None,
    *, device=None
):
    """
    Return a full array with the same shape and type as a given array.

    Parameters
    ----------
    a : array_like
        The shape and data-type of `a` define these same attributes of
        the returned array.
    fill_value : array_like
        Fill value.
    dtype : data-type, optional
        Overrides the data type of the result.

    """
    # 创建一个与输入数组 `a` 相同形状和类型的新数组,使用指定的填充值 `fill_value`
    res = empty_like(
        a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
    )
    # 将 `fill_value` 的值复制到新创建的数组 `res` 中,使用不安全的类型转换
    multiarray.copyto(res, fill_value, casting='unsafe')
    # 返回填充后的新数组 `res`
    return res
# 定义一个分发器函数,用于向 `count_nonzero` 函数分发参数 `a`
def _count_nonzero_dispatcher(a, axis=None, *, keepdims=None):
    # 返回一个元组,包含参数 `a`,其他参数为默认值
    return (a,)


# 使用装饰器 `array_function_dispatch` 装饰的 `count_nonzero` 函数
@array_function_dispatch(_count_nonzero_dispatcher)
def count_nonzero(a, axis=None, *, keepdims=False):
    """
    Counts the number of non-zero values in the array `a`.

    The word "non-zero" is in reference to the Python 2.x
    built-in method `__nonzero__()` (renamed `__bool__()`
    in Python 3.x) of Python objects that tests an object's
    "truthfulness". For example, any number is considered
    truthful if it is nonzero, whereas any string is considered
    truthful if it is not the empty string. Thus, this function
    (recursively) counts how many elements in `a` (and in
    sub-arrays thereof) have their `__nonzero__()` or `__bool__()`
    method evaluated to `True`.

    Parameters
    ----------
    a : array_like
        The array for which to count non-zeros.
    axis : int or tuple, optional
        Axis or tuple of axes along which to count non-zeros.
        Default is None, meaning that non-zeros will be counted
        along a flattened version of `a`.

        .. versionadded:: 1.12.0

    keepdims : bool, optional
        If this is set to True, the axes that are counted are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the input array.

        .. versionadded:: 1.19.0

    Returns
    -------
    count : int or array of int
        Number of non-zero values in the array along a given axis.
        Otherwise, the total number of non-zero values in the array
        is returned.

    See Also
    --------
    nonzero : Return the coordinates of all the non-zero values.

    Examples
    --------
    >>> np.count_nonzero(np.eye(4))
    4
    >>> a = np.array([[0, 1, 7, 0],
    ...               [3, 0, 2, 19]])
    >>> np.count_nonzero(a)
    5
    >>> np.count_nonzero(a, axis=0)
    array([1, 1, 2, 1])
    >>> np.count_nonzero(a, axis=1)
    array([2, 3])
    >>> np.count_nonzero(a, axis=1, keepdims=True)
    array([[2],
           [3]])
    """
    # 如果 `axis` 为 None 并且 `keepdims` 为 False,则调用 `multiarray.count_nonzero` 函数
    if axis is None and not keepdims:
        return multiarray.count_nonzero(a)

    # 将 `a` 转换为 `ndarray` 类型
    a = asanyarray(a)

    # TODO: this works around .astype(bool) not working properly (gh-9847)
    # 如果 `a` 的数据类型为字符类型,则创建一个布尔类型的数组 `a_bool`
    if np.issubdtype(a.dtype, np.character):
        a_bool = a != a.dtype.type()
    else:
        # 否则,将 `a` 转换为布尔类型的数组 `a_bool`
        a_bool = a.astype(np.bool, copy=False)

    # 返回沿指定轴(如果有)求和后的布尔类型数组 `a_bool`,结果的数据类型为 `np.intp`
    return a_bool.sum(axis=axis, dtype=np.intp, keepdims=keepdims)


# 使用装饰器 `set_module` 装饰的 `isfortran` 函数
@set_module('numpy')
def isfortran(a):
    """
    Check if the array is Fortran contiguous but *not* C contiguous.

    This function is obsolete. If you only want to check if an array is Fortran
    contiguous use `a.flags.f_contiguous` instead.

    Parameters
    ----------
    a : ndarray
        Input array.

    Returns
    -------
    isfortran : bool
        Returns True if the array is Fortran contiguous but *not* C contiguous.


    Examples
    --------
    np.array allows to specify whether the array is written in C-contiguous
    order (last index varies the fastest), or FORTRAN-contiguous order in
    memory (first index varies the fastest).

    >>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C')
    >>> a
    array([[1, 2, 3],
           [4, 5, 6]])
    >>> np.isfortran(a)
    False

    >>> b = np.array([[1, 2, 3], [4, 5, 6]], order='F')
    >>> b
    array([[1, 2, 3],
           [4, 5, 6]])
    >>> np.isfortran(b)
    True


    The transpose of a C-ordered array is a FORTRAN-ordered array.

    >>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C')
    >>> a
    array([[1, 2, 3],
           [4, 5, 6]])
    >>> np.isfortran(a)
    False
    >>> b = a.T
    >>> b
    array([[1, 4],
           [2, 5],
           [3, 6]])
    >>> np.isfortran(b)
    True

    C-ordered arrays evaluate as False even if they are also FORTRAN-ordered.

    >>> np.isfortran(np.array([1, 2], order='F'))
    False

    """
    # 返回数组 a 的 flags 属性中的 fnc 属性值
    return a.flags.fnc
# 定义一个函数分派器,用于返回输入参数元组
def _argwhere_dispatcher(a):
    return (a,)

# 使用装饰器将_dispatcher函数与argwhere函数关联,用于根据输入类型调度函数
@array_function_dispatch(_argwhere_dispatcher)
def argwhere(a):
    """
    Find the indices of array elements that are non-zero, grouped by element.

    Parameters
    ----------
    a : array_like
        Input data.

    Returns
    -------
    index_array : (N, a.ndim) ndarray
        Indices of elements that are non-zero. Indices are grouped by element.
        This array will have shape ``(N, a.ndim)`` where ``N`` is the number of
        non-zero items.

    See Also
    --------
    where, nonzero

    Notes
    -----
    ``np.argwhere(a)`` is almost the same as ``np.transpose(np.nonzero(a))``,
    but produces a result of the correct shape for a 0D array.

    The output of ``argwhere`` is not suitable for indexing arrays.
    For this purpose use ``nonzero(a)`` instead.

    Examples
    --------
    >>> x = np.arange(6).reshape(2,3)
    >>> x
    array([[0, 1, 2],
           [3, 4, 5]])
    >>> np.argwhere(x>1)
    array([[0, 2],
           [1, 0],
           [1, 1],
           [1, 2]])

    """
    # 如果输入数组a的维度为0,则提升为至少1维数组
    if np.ndim(a) == 0:
        a = shape_base.atleast_1d(a)
        # 然后去除添加的维度
        return argwhere(a)[:, :0]
    # 返回数组a中非零元素的索引数组,索引按元素分组
    return transpose(nonzero(a))


# 定义一个函数分派器,用于返回输入参数元组
def _flatnonzero_dispatcher(a):
    return (a,)

# 使用装饰器将_dispatcher函数与flatnonzero函数关联,用于根据输入类型调度函数
@array_function_dispatch(_flatnonzero_dispatcher)
def flatnonzero(a):
    """
    Return indices that are non-zero in the flattened version of a.

    This is equivalent to ``np.nonzero(np.ravel(a))[0]``.

    Parameters
    ----------
    a : array_like
        Input data.

    Returns
    -------
    res : ndarray
        Output array, containing the indices of the elements of ``a.ravel()``
        that are non-zero.

    See Also
    --------
    nonzero : Return the indices of the non-zero elements of the input array.
    ravel : Return a 1-D array containing the elements of the input array.

    Examples
    --------
    >>> x = np.arange(-2, 3)
    >>> x
    array([-2, -1,  0,  1,  2])
    >>> np.flatnonzero(x)
    array([0, 1, 3, 4])

    Use the indices of the non-zero elements as an index array to extract
    these elements:

    >>> x.ravel()[np.flatnonzero(x)]
    array([-2, -1,  1,  2])

    """
    # 返回数组a的扁平化版本中非零元素的索引数组
    return np.nonzero(np.ravel(a))[0]


# 定义一个函数分派器,用于返回输入参数元组
def _correlate_dispatcher(a, v, mode=None):
    return (a, v)

# 使用装饰器将_dispatcher函数与correlate函数关联,用于根据输入类型调度函数
@array_function_dispatch(_correlate_dispatcher)
def correlate(a, v, mode='valid'):
    r"""
    Cross-correlation of two 1-dimensional sequences.

    This function computes the correlation as generally defined in signal
    processing texts [1]_:

    .. math:: c_k = \sum_n a_{n+k} \cdot \overline{v}_n

    with a and v sequences being zero-padded where necessary and
    :math:`\overline v` denoting complex conjugation.

    Parameters
    ----------
    a, v : array_like
        Input sequences.
    mode : {'valid', 'same', 'full'}, optional
        # 模式参数,指定交叉相关计算的模式,可以是'valid'、'same'、'full'
        Refer to the `convolve` docstring.  Note that the default
        # 参考`convolve`函数的文档字符串,注意默认值为'valid',而不是`convolve`函数的'full'
        is 'valid', unlike `convolve`, which uses 'full'.

    Returns
    -------
    out : ndarray
        # 返回值为 ndarray 类型,表示输入数组 a 和 v 的离散交叉相关结果
        Discrete cross-correlation of `a` and `v`.

    See Also
    --------
    convolve : Discrete, linear convolution of two one-dimensional sequences.
    scipy.signal.correlate : uses FFT which has superior performance
        on large arrays.
        # 参见函数 convolve:计算两个一维序列的离散线性卷积。
        # scipy.signal.correlate 使用 FFT 在大数组上有更优越的性能表现。

    Notes
    -----
    The definition of correlation above is not unique and sometimes
    correlation may be defined differently. Another common definition is [1]_:

    .. math:: c'_k = \sum_n a_{n} \cdot \overline{v_{n+k}}

    which is related to :math:`c_k` by :math:`c'_k = c_{-k}`.
        # 上述的相关定义不是唯一的,有时可能会有不同的定义。另一个常见的定义如 [1] 所示:
        # 这与 c_k 的关系由 c'_k = c_{-k} 给出。

    `numpy.correlate` may perform slowly in large arrays (i.e. n = 1e5)
    because it does not use the FFT to compute the convolution; in that case,
    `scipy.signal.correlate` might be preferable.
        # 在大数组(例如 n = 1e5)上,`numpy.correlate` 的性能可能较慢,
        # 因为它不使用 FFT 来计算卷积;在这种情况下,可能更倾向于使用 `scipy.signal.correlate`。

    References
    ----------
    .. [1] Wikipedia, "Cross-correlation",
           https://en.wikipedia.org/wiki/Cross-correlation
        # 参考文献 [1]:Wikipedia,"Cross-correlation",链接地址为 https://en.wikipedia.org/wiki/Cross-correlation

    Examples
    --------
    >>> np.correlate([1, 2, 3], [0, 1, 0.5])
    array([3.5])
    >>> np.correlate([1, 2, 3], [0, 1, 0.5], "same")
    array([2. ,  3.5,  3. ])
    >>> np.correlate([1, 2, 3], [0, 1, 0.5], "full")
    array([0.5,  2. ,  3.5,  3. ,  0. ])
        # 使用示例:计算不同模式下的离散交叉相关结果

    Using complex sequences:

    >>> np.correlate([1+1j, 2, 3-1j], [0, 1, 0.5j], 'full')
    array([ 0.5-0.5j,  1.0+0.j ,  1.5-1.5j,  3.0-1.j ,  0.0+0.j ])
        # 使用复数序列的示例:计算复数序列的离散交叉相关结果

    Note that you get the time reversed, complex conjugated result
    (:math:`\overline{c_{-k}}`) when the two input sequences a and v change
    places:

    >>> np.correlate([0, 1, 0.5j], [1+1j, 2, 3-1j], 'full')
    array([ 0.0+0.j ,  3.0+1.j ,  1.5+1.5j,  1.0+0.j ,  0.5+0.5j])
        # 注意:当输入序列 a 和 v 位置交换时,得到的结果是时间反转、复共轭的结果 `c_{-k}`

    """
    return multiarray.correlate2(a, v, mode)
        # 调用 multiarray 模块的 correlate2 函数,计算输入数组 a 和 v 的离散交叉相关结果
# 定义一个调度函数,用于派发输入给卷积函数
def _convolve_dispatcher(a, v, mode=None):
    # 返回输入参数 a 和 v 的元组
    return (a, v)


# 使用装饰器 array_function_dispatch 将 _convolve_dispatcher 函数与 convolve 函数关联起来
@array_function_dispatch(_convolve_dispatcher)
def convolve(a, v, mode='full'):
    """
    Returns the discrete, linear convolution of two one-dimensional sequences.

    The convolution operator is often seen in signal processing, where it
    models the effect of a linear time-invariant system on a signal [1]_.  In
    probability theory, the sum of two independent random variables is
    distributed according to the convolution of their individual
    distributions.

    If `v` is longer than `a`, the arrays are swapped before computation.

    Parameters
    ----------
    a : (N,) array_like
        First one-dimensional input array.
    v : (M,) array_like
        Second one-dimensional input array.
    mode : {'full', 'valid', 'same'}, optional
        'full':
          By default, mode is 'full'.  This returns the convolution
          at each point of overlap, with an output shape of (N+M-1,). At
          the end-points of the convolution, the signals do not overlap
          completely, and boundary effects may be seen.

        'same':
          Mode 'same' returns output of length ``max(M, N)``.  Boundary
          effects are still visible.

        'valid':
          Mode 'valid' returns output of length
          ``max(M, N) - min(M, N) + 1``.  The convolution product is only given
          for points where the signals overlap completely.  Values outside
          the signal boundary have no effect.

    Returns
    -------
    out : ndarray
        Discrete, linear convolution of `a` and `v`.

    See Also
    --------
    scipy.signal.fftconvolve : Convolve two arrays using the Fast Fourier
                               Transform.
    scipy.linalg.toeplitz : Used to construct the convolution operator.
    polymul : Polynomial multiplication. Same output as convolve, but also
              accepts poly1d objects as input.

    Notes
    -----
    The discrete convolution operation is defined as

    .. math:: (a * v)_n = \\sum_{m = -\\infty}^{\\infty} a_m v_{n - m}

    It can be shown that a convolution :math:`x(t) * y(t)` in time/space
    is equivalent to the multiplication :math:`X(f) Y(f)` in the Fourier
    domain, after appropriate padding (padding is necessary to prevent
    circular convolution).  Since multiplication is more efficient (faster)
    than convolution, the function `scipy.signal.fftconvolve` exploits the
    FFT to calculate the convolution of large data-sets.

    References
    ----------
    .. [1] Wikipedia, "Convolution",
        https://en.wikipedia.org/wiki/Convolution

    Examples
    --------
    Note how the convolution operator flips the second array
    before "sliding" the two across one another:

    >>> np.convolve([1, 2, 3], [0, 1, 0.5])
    array([0. , 1. , 2.5, 4. , 1.5])

    Only return the middle values of the convolution.
    Contains boundary effects, where zeros are taken
    into account:
    """
    # 返回函数的主体部分,用于执行一维序列的线性离散卷积
    pass
    # 使用 NumPy 的卷积函数 convolve 对数组 a 和 v 进行卷积运算,并返回指定模式下的结果
    >>> np.convolve([1,2,3],[0,1,0.5], 'same')
    # 在 'same' 模式下,返回与输入数组相同长度的卷积结果
    array([1. ,  2.5,  4. ])

    # 由于两个数组长度相同,因此只有一个位置完全重叠:
    >>> np.convolve([1,2,3],[0,1,0.5], 'valid')
    # 在 'valid' 模式下,返回完全重叠部分的卷积结果
    array([2.5])

    """
    # 将输入的数组 a 和 v 转换为 NumPy 数组,并确保它们至少是一维的
    a, v = array(a, copy=None, ndmin=1), array(v, copy=None, ndmin=1)
    # 如果 v 的长度大于 a,则交换它们,确保 a 是长度较长的数组
    if (len(v) > len(a)):
        a, v = v, a
    # 如果 a 的长度为 0,则抛出值错误异常
    if len(a) == 0:
        raise ValueError('a cannot be empty')
    # 如果 v 的长度为 0,则抛出值错误异常
    if len(v) == 0:
        raise ValueError('v cannot be empty')
    # 调用 NumPy 的多维数组库的 correlate 函数,对 a 和 v 进行相关运算,使用反转的 v,并返回指定 mode 的结果
    return multiarray.correlate(a, v[::-1], mode)
# 创建一个元组,包含三个输入参数 a, b, out(可选)
def _outer_dispatcher(a, b, out=None):
    return (a, b, out)

# 使用 array_function_dispatch 装饰器注册 _outer_dispatcher 函数
@array_function_dispatch(_outer_dispatcher)
# 定义 outer 函数,计算两个向量的外积
def outer(a, b, out=None):
    """
    计算两个向量的外积。

    给定长度分别为 ``M`` 和 ``N`` 的两个向量 `a` 和 `b`,外积 [1]_ 定义为::

      [[a_0*b_0  a_0*b_1 ... a_0*b_{N-1} ]
       [a_1*b_0    .
       [ ...          .
       [a_{M-1}*b_0            a_{M-1}*b_{N-1} ]]

    Parameters
    ----------
    a : (M,) array_like
        第一个输入向量。如果不是已经是 1 维的,则会被扁平化。
    b : (N,) array_like
        第二个输入向量。如果不是已经是 1 维的,则会被扁平化。
    out : (M, N) ndarray, optional
        结果存储的位置

        .. versionadded:: 1.9.0

    Returns
    -------
    out : (M, N) ndarray
        ``out[i, j] = a[i] * b[j]``

    See also
    --------
    inner
    einsum : ``einsum('i,j->ij', a.ravel(), b.ravel())`` 的等价形式。
    ufunc.outer : 对于维度不限于 1D 和其他操作的泛化版本。``np.multiply.outer(a.ravel(), b.ravel())``
                  是其等价形式。
    linalg.outer : ``np.outer`` 的一个兼容 Array API 的变体,仅接受 1 维输入。
    tensordot : ``np.tensordot(a.ravel(), b.ravel(), axes=((), ()))``
                是其等价形式。

    References
    ----------
    .. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*, 3rd
           ed., Baltimore, MD, Johns Hopkins University Press, 1996,
           pg. 8.

    Examples
    --------
    创建一个 (*非常粗糙的*) 网格来计算 Mandelbrot 集合:

    >>> rl = np.outer(np.ones((5,)), np.linspace(-2, 2, 5))
    >>> rl
    array([[-2., -1.,  0.,  1.,  2.],
           [-2., -1.,  0.,  1.,  2.],
           [-2., -1.,  0.,  1.,  2.],
           [-2., -1.,  0.,  1.,  2.],
           [-2., -1.,  0.,  1.,  2.]])
    >>> im = np.outer(1j*np.linspace(2, -2, 5), np.ones((5,)))
    >>> im
    array([[0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j],
           [0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j],
           [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
           [0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j],
           [0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j]])
    >>> grid = rl + im
    >>> grid
    array([[-2.+2.j, -1.+2.j,  0.+2.j,  1.+2.j,  2.+2.j],
           [-2.+1.j, -1.+1.j,  0.+1.j,  1.+1.j,  2.+1.j],
           [-2.+0.j, -1.+0.j,  0.+0.j,  1.+0.j,  2.+0.j],
           [-2.-1.j, -1.-1.j,  0.-1.j,  1.-1.j,  2.-1.j],
           [-2.-2.j, -1.-2.j,  0.-2.j,  1.-2.j,  2.-2.j]])

    使用一个字母的 "向量" 的示例:

    >>> x = np.array(['a', 'b', 'c'], dtype=object)
    >>> np.outer(x, [1, 2, 3])
    array([['a', 'aa', 'aaa'],
           ['b', 'bb', 'bbb'],
           ['c', 'cc', 'ccc']], dtype=object)

    """
    # 将输入向量 a 和 b 转换为数组
    a = asarray(a)
    b = asarray(b)
    # 返回 a 和 b 的外积,结果存储在 out 中
    return multiply(a.ravel()[:, newaxis], b.ravel()[newaxis, :], out)
# 定义函数_tensordot_dispatcher,接收参数a, b, axes,并直接返回元组(a, b)
def _tensordot_dispatcher(a, b, axes=None):
    return (a, b)

# 使用array_function_dispatch装饰器将函数_tensordot_dispatcher注册为tensordot的分派函数
@array_function_dispatch(_tensordot_dispatcher)
# 定义函数tensordot,实现张量的点乘操作
def tensordot(a, b, axes=2):
    """
    Compute tensor dot product along specified axes.

    Given two tensors, `a` and `b`, and an array_like object containing
    two array_like objects, ``(a_axes, b_axes)``, sum the products of
    `a`'s and `b`'s elements (components) over the axes specified by
    ``a_axes`` and ``b_axes``. The third argument can be a single non-negative
    integer_like scalar, ``N``; if it is such, then the last ``N`` dimensions
    of `a` and the first ``N`` dimensions of `b` are summed over.

    Parameters
    ----------
    a, b : array_like
        Tensors to "dot".

    axes : int or (2,) array_like
        * integer_like
          If an int N, sum over the last N axes of `a` and the first N axes
          of `b` in order. The sizes of the corresponding axes must match.
        * (2,) array_like
          Or, a list of axes to be summed over, first sequence applying to `a`,
          second to `b`. Both elements array_like must be of the same length.

    Returns
    -------
    output : ndarray
        The tensor dot product of the input.

    See Also
    --------
    dot, einsum

    Notes
    -----
    Three common use cases are:

    * ``axes = 0`` : tensor product :math:`a\\otimes b`
    * ``axes = 1`` : tensor dot product :math:`a\\cdot b`
    * ``axes = 2`` : (default) tensor double contraction :math:`a:b`

    When `axes` is a positive integer ``N``, the operation starts with
    axis ``-N`` of `a` and axis ``0`` of `b`, and it continues through
    axis ``-1`` of `a` and axis ``N-1`` of `b` (inclusive).

    When there is more than one axis to sum over - and they are not the last
    (first) axes of `a` (`b`) - the argument `axes` should consist of
    two sequences of the same length, with the first axis to sum over given
    first in both sequences, the second axis second, and so forth.

    The shape of the result consists of the non-contracted axes of the
    first tensor, followed by the non-contracted axes of the second.

    Examples
    --------
    A "traditional" example:

    >>> a = np.arange(60.).reshape(3,4,5)
    >>> b = np.arange(24.).reshape(4,3,2)
    >>> c = np.tensordot(a,b, axes=([1,0],[0,1]))
    >>> c.shape
    (5, 2)
    >>> c
    array([[4400., 4730.],
           [4532., 4874.],
           [4664., 5018.],
           [4796., 5162.],
           [4928., 5306.]])
    >>> # A slower but equivalent way of computing the same...
    >>> d = np.zeros((5,2))
    >>> for i in range(5):
    ...   for j in range(2):
    ...     for k in range(3):
    ...       for n in range(4):
    ...         d[i,j] += a[k,n,i] * b[n,k,j]
    >>> c == d
    array([[ True,  True],
           [ True,  True],
           [ True,  True],
           [ True,  True],
           [ True,  True]])

    An extended example taking advantage of the overloading of + and \\*:

    >>> a = np.array(range(1, 9))
    """
    # 函数的具体实现在array_function_dispatch中定义的分派函数中完成,此处不作具体实现
    pass
    # 将数组 a 的形状改变为 (2, 2, 2)
    >>> a.shape = (2, 2, 2)
    # 创建一个包含对象类型数据 ('a', 'b', 'c', 'd') 的数组 A,将其形状改变为 (2, 2)
    >>> A = np.array(('a', 'b', 'c', 'd'), dtype=object)
    >>> A.shape = (2, 2)
    # 打印数组 a 和数组 A
    >>> a; A
    array([[[1, 2],
            [3, 4]],
           [[5, 6],
            [7, 8]]])
    array([['a', 'b'],
           ['c', 'd']], dtype=object)
    
    # 对数组 a 和数组 A 进行张量点乘,默认使用双重收缩的第三个参数为 2
    >>> np.tensordot(a, A)
    array(['abbcccdddd', 'aaaaabbbbbbcccccccdddddddd'], dtype=object)
    
    # 对数组 a 和数组 A 进行张量点乘,指定第三个参数为 1
    >>> np.tensordot(a, A, 1)
    array([[['acc', 'bdd'],
            ['aaacccc', 'bbbdddd']],
           [['aaaaacccccc', 'bbbbbdddddd'],
            ['aaaaaaacccccccc', 'bbbbbbbdddddddd']]], dtype=object)
    
    # 对数组 a 和数组 A 进行张量积,结果太长未包含在此处
    >>> np.tensordot(a, A, 0)
    array([[[[['a', 'b'],
              ['c', 'd']],
             ...
    
    # 对数组 a 和数组 A 进行张量点乘,指定收缩的轴为 (0, 1)
    >>> np.tensordot(a, A, (0, 1))
    array([[['abbbbb', 'cddddd'],
            ['aabbbbbb', 'ccdddddd']],
           [['aaabbbbbbb', 'cccddddddd'],
            ['aaaabbbbbbbb', 'ccccdddddddd']]], dtype=object)
    
    # 对数组 a 和数组 A 进行张量点乘,指定收缩的轴为 (2, 1)
    >>> np.tensordot(a, A, (2, 1))
    array([[['abb', 'cdd'],
            ['aaabbbb', 'cccdddd']],
           [['aaaaabbbbbb', 'cccccdddddd'],
            ['aaaaaaabbbbbbbb', 'cccccccdddddddd']]], dtype=object)
    
    # 对数组 a 和数组 A 进行张量点乘,同时指定多个收缩的轴为 ((0, 1), (0, 1))
    >>> np.tensordot(a, A, ((0, 1), (0, 1)))
    array(['abbbcccccddddddd', 'aabbbbccccccdddddddd'], dtype=object)
    
    # 对数组 a 和数组 A 进行张量点乘,同时指定多个收缩的轴为 ((2, 1), (1, 0))
    >>> np.tensordot(a, A, ((2, 1), (1, 0)))
    array(['acccbbdddd', 'aaaaacccccccbbbbbbdddddddd'], dtype=object)
    
    try:
        iter(axes)
    except Exception:
        # 如果 axes 不可迭代,说明是一个整数
        axes_a = list(range(-axes, 0))
        axes_b = list(range(0, axes))
    else:
        # 如果 axes 可迭代,分别赋值给 axes_a 和 axes_b
        axes_a, axes_b = axes
    
    try:
        # 尝试获取 axes_a 的长度,并转换为列表
        na = len(axes_a)
        axes_a = list(axes_a)
    except TypeError:
        # 如果无法获取长度,说明 axes_a 只包含一个整数,将其转为列表形式
        axes_a = [axes_a]
        na = 1
    
    try:
        # 尝试获取 axes_b 的长度,并转换为列表
        nb = len(axes_b)
        axes_b = list(axes_b)
    except TypeError:
        # 如果无法获取长度,说明 axes_b 只包含一个整数,将其转为列表形式
        axes_b = [axes_b]
        nb = 1
    
    # 将数组 a 和 b 转换为数组,并获取它们的形状和维度
    a, b = asarray(a), asarray(b)
    as_ = a.shape
    nda = a.ndim
    bs = b.shape
    ndb = b.ndim
    equal = True
    
    # 检查 axes_a 和 axes_b 的长度是否相等,如果不相等则抛出 ValueError
    if na != nb:
        equal = False
    else:
        # 遍历 axes_a 和 axes_b,检查对应轴的形状是否相等
        for k in range(na):
            if as_[axes_a[k]] != bs[axes_b[k]]:
                equal = False
                break
            # 处理负索引,将其转换为正索引
            if axes_a[k] < 0:
                axes_a[k] += nda
            if axes_b[k] < 0:
                axes_b[k] += ndb
    
    # 如果形状不匹配,则抛出 ValueError
    if not equal:
        raise ValueError("shape-mismatch for sum")
    
    # 将要进行收缩的轴移到数组 a 的末尾,移到数组 b 的前面
    notin = [k for k in range(nda) if k not in axes_a]
    newaxes_a = notin + axes_a
    # 计算新形状和旧形状
    N2 = math.prod(as_[axis] for axis in axes_a)
    newshape_a = (math.prod([as_[ax] for ax in notin]), N2)
    olda = [as_[axis] for axis in notin]
    
    # 将要进行收缩的轴移到数组 b 的前面,移到数组 b 的末尾
    notin = [k for k in range(ndb) if k not in axes_b]
    newaxes_b = axes_b + notin
    # 计算新形状和旧形状
    N2 = math.prod(bs[axis] for axis in axes_b)
    newshape_b = (N2, math.prod([bs[ax] for ax in notin]))
    oldb = [bs[axis] for axis in notin]
    
    # 对数组 a 根据 newaxes_a 进行转置,并重新调整形状为 newshape_a
    at = a.transpose(newaxes_a).reshape(newshape_a)
    # 将数组 b 按照 newaxes_b 指定的轴顺序进行转置,并按照 newshape_b 指定的形状进行重塑
    bt = b.transpose(newaxes_b).reshape(newshape_b)
    # 计算矩阵 a 和重塑后的矩阵 bt 的矩阵乘积
    res = dot(at, bt)
    # 将结果重新按照原来的形状 olda + oldb 进行重塑并返回
    return res.reshape(olda + oldb)
# 定义一个私有函数 _roll_dispatcher,用于分派数组滚动操作
def _roll_dispatcher(a, shift, axis=None):
    # 返回一个元组,包含参数 a
    return (a,)


# 使用装饰器 @array_function_dispatch 将 roll 函数与 _roll_dispatcher 关联起来,
# 用于数组滚动操作的分派
@array_function_dispatch(_roll_dispatcher)
def roll(a, shift, axis=None):
    """
    Roll array elements along a given axis.

    Elements that roll beyond the last position are re-introduced at
    the first.

    Parameters
    ----------
    a : array_like
        Input array.
    shift : int or tuple of ints
        The number of places by which elements are shifted.  If a tuple,
        then `axis` must be a tuple of the same size, and each of the
        given axes is shifted by the corresponding number.  If an int
        while `axis` is a tuple of ints, then the same value is used for
        all given axes.
    axis : int or tuple of ints, optional
        Axis or axes along which elements are shifted.  By default, the
        array is flattened before shifting, after which the original
        shape is restored.

    Returns
    -------
    res : ndarray
        Output array, with the same shape as `a`.

    See Also
    --------
    rollaxis : Roll the specified axis backwards, until it lies in a
               given position.

    Notes
    -----
    .. versionadded:: 1.12.0

    Supports rolling over multiple dimensions simultaneously.

    Examples
    --------
    >>> x = np.arange(10)
    >>> np.roll(x, 2)
    array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
    >>> np.roll(x, -2)
    array([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])

    >>> x2 = np.reshape(x, (2, 5))
    >>> x2
    array([[0, 1, 2, 3, 4],
           [5, 6, 7, 8, 9]])
    >>> np.roll(x2, 1)
    array([[9, 0, 1, 2, 3],
           [4, 5, 6, 7, 8]])
    >>> np.roll(x2, -1)
    array([[1, 2, 3, 4, 5],
           [6, 7, 8, 9, 0]])
    >>> np.roll(x2, 1, axis=0)
    array([[5, 6, 7, 8, 9],
           [0, 1, 2, 3, 4]])
    >>> np.roll(x2, -1, axis=0)
    array([[5, 6, 7, 8, 9],
           [0, 1, 2, 3, 4]])
    >>> np.roll(x2, 1, axis=1)
    array([[4, 0, 1, 2, 3],
           [9, 5, 6, 7, 8]])
    >>> np.roll(x2, -1, axis=1)
    array([[1, 2, 3, 4, 0],
           [6, 7, 8, 9, 5]])
    >>> np.roll(x2, (1, 1), axis=(1, 0))
    array([[9, 5, 6, 7, 8],
           [4, 0, 1, 2, 3]])
    >>> np.roll(x2, (2, 1), axis=(1, 0))
    array([[8, 9, 5, 6, 7],
           [3, 4, 0, 1, 2]])

    """
    # 将输入转换为数组
    a = asanyarray(a)
    # 如果未指定轴向,则将数组展平后再进行滚动操作,最后恢复原始形状
    if axis is None:
        return roll(a.ravel(), shift, 0).reshape(a.shape)
    else:
        # 规范化轴参数,允许重复,并返回规范化后的轴元组
        axis = normalize_axis_tuple(axis, a.ndim, allow_duplicate=True)
        # 对 shift 进行广播,使其与 axis 兼容
        broadcasted = broadcast(shift, axis)
        # 如果广播后的维度大于 1,抛出 ValueError 异常
        if broadcasted.ndim > 1:
            raise ValueError(
                "'shift' and 'axis' should be scalars or 1D sequences")
        # 初始化一个字典 shifts,用于存储每个轴的偏移量
        shifts = {ax: 0 for ax in range(a.ndim)}
        # 遍历广播后的偏移量和对应的轴,并累加到 shifts 字典中
        for sh, ax in broadcasted:
            shifts[ax] += sh

        # 初始化 rolls 列表,每个元素都是一个元组,用于描述切片操作
        rolls = [((slice(None), slice(None)),)] * a.ndim
        # 遍历 shifts 字典中的每个轴和对应的偏移量
        for ax, offset in shifts.items():
            # 计算偏移量取模后的值,如果 a 是空的,则取 1
            offset %= a.shape[ax] or 1  # If `a` is empty, nothing matters.
            # 如果偏移量不为 0,则更新 rolls 列表中对应轴的切片操作元组
            if offset:
                # 更新 rolls 中对应轴的切片操作
                rolls[ax] = ((slice(None, -offset), slice(offset, None)),
                             (slice(-offset, None), slice(None, offset)))

        # 初始化结果数组,形状与 a 相同
        result = empty_like(a)
        # 使用 itertools.product 遍历 rolls 中所有可能的索引组合
        for indices in itertools.product(*rolls):
            # 将 arr_index 和 res_index 分别解压缩为两个元组
            arr_index, res_index = zip(*indices)
            # 将 a 中的数据根据 arr_index 复制到 result 的对应位置 res_index
            result[res_index] = a[arr_index]

        # 返回结果数组
        return result
# 根据传入的参数 `a`、`axis` 和可选参数 `start` 确定派发函数的实现。
def _rollaxis_dispatcher(a, axis, start=None):
    # 返回包含 `a` 的元组,作为派发函数的结果
    return (a,)

# 使用装饰器 `array_function_dispatch` 来声明 `rollaxis` 函数的分派规则
@array_function_dispatch(_rollaxis_dispatcher)
def rollaxis(a, axis, start=0):
    """
    Roll the specified axis backwards, until it lies in a given position.

    This function continues to be supported for backward compatibility, but you
    should prefer `moveaxis`. The `moveaxis` function was added in NumPy
    1.11.

    Parameters
    ----------
    a : ndarray
        Input array.
    axis : int
        The axis to be rolled. The positions of the other axes do not
        change relative to one another.
    start : int, optional
        When ``start <= axis``, the axis is rolled back until it lies in
        this position. When ``start > axis``, the axis is rolled until it
        lies before this position. The default, 0, results in a "complete"
        roll. The following table describes how negative values of ``start``
        are interpreted:

        .. table::
           :align: left

           +-------------------+----------------------+
           |     ``start``     | Normalized ``start`` |
           +===================+======================+
           | ``-(arr.ndim+1)`` | raise ``AxisError``  |
           +-------------------+----------------------+
           | ``-arr.ndim``     | 0                    |
           +-------------------+----------------------+
           | |vdots|           | |vdots|              |
           +-------------------+----------------------+
           | ``-1``            | ``arr.ndim-1``       |
           +-------------------+----------------------+
           | ``0``             | ``0``                |
           +-------------------+----------------------+
           | |vdots|           | |vdots|              |
           +-------------------+----------------------+
           | ``arr.ndim``      | ``arr.ndim``         |
           +-------------------+----------------------+
           | ``arr.ndim + 1``  | raise ``AxisError``  |
           +-------------------+----------------------+

        .. |vdots|   unicode:: U+22EE .. Vertical Ellipsis

    Returns
    -------
    res : ndarray
        For NumPy >= 1.10.0 a view of `a` is always returned. For earlier
        NumPy versions a view of `a` is returned only if the order of the
        axes is changed, otherwise the input array is returned.

    See Also
    --------
    moveaxis : Move array axes to new positions.
    roll : Roll the elements of an array by a number of positions along a
        given axis.

    Examples
    --------
    >>> a = np.ones((3,4,5,6))
    >>> np.rollaxis(a, 3, 1).shape
    (3, 6, 4, 5)
    >>> np.rollaxis(a, 2).shape
    (5, 3, 4, 6)
    >>> np.rollaxis(a, 1, 4).shape
    (3, 5, 6, 4)

    """
    # 获取数组 `a` 的维度数
    n = a.ndim
    # 标准化 `axis`,确保其在合法范围内
    axis = normalize_axis_index(axis, n)
    # 处理 `start` 参数为负数的情况,将其转换为非负数索引
    if start < 0:
        start += n
    # 创建错误消息模板,用于验证 `start` 参数的合法性
    msg = "'%s' arg requires %d <= %s < %d, but %d was passed in"
    # 检查起始索引是否在合法范围内(0到n之间),如果不是则引发 AxisError 异常
    if not (0 <= start < n + 1):
        raise AxisError(msg % ('start', -n, 'start', n + 1, start))
    
    # 如果轴(axis)小于起始索引(start),说明轴已被移除,需要将起始索引减一
    if axis < start:
        # it's been removed
        start -= 1
    
    # 如果轴(axis)等于起始索引(start),直接返回整个数组 a
    if axis == start:
        return a[...]
    
    # 创建一个包含从 0 到 n-1 的整数列表,表示所有轴的索引
    axes = list(range(0, n))
    
    # 从 axes 列表中移除原始轴(axis)
    axes.remove(axis)
    
    # 将轴(axis)插入到起始索引(start)的位置
    axes.insert(start, axis)
    
    # 根据重新排列的轴顺序进行数组 a 的转置操作,并返回结果
    return a.transpose(axes)
# 设置函数的模块为 "numpy.lib.array_utils"
@set_module("numpy.lib.array_utils")
def normalize_axis_tuple(axis, ndim, argname=None, allow_duplicate=False):
    """
    Normalizes an axis argument into a tuple of non-negative integer axes.

    This handles shorthands such as ``1`` and converts them to ``(1,)``,
    as well as performing the handling of negative indices covered by
    `normalize_axis_index`.

    By default, this forbids axes from being specified multiple times.

    Used internally by multi-axis-checking logic.

    .. versionadded:: 1.13.0

    Parameters
    ----------
    axis : int, iterable of int
        The un-normalized index or indices of the axis.
    ndim : int
        The number of dimensions of the array that `axis` should be normalized
        against.
    argname : str, optional
        A prefix to put before the error message, typically the name of the
        argument.
    allow_duplicate : bool, optional
        If False, the default, disallow an axis from being specified twice.

    Returns
    -------
    normalized_axes : tuple of int
        The normalized axis index, such that `0 <= normalized_axis < ndim`

    Raises
    ------
    AxisError
        If any axis provided is out of range
    ValueError
        If an axis is repeated

    See also
    --------
    normalize_axis_index : normalizing a single scalar axis
    """
    # 如果 axis 不是 tuple 或 list 类型,尝试将其转换为包含单个元素的列表
    if type(axis) not in (tuple, list):
        try:
            axis = [operator.index(axis)]
        except TypeError:
            pass
    # 使用列表推导式对每个轴进行归一化处理,返回一个元组
    axis = tuple([normalize_axis_index(ax, ndim, argname) for ax in axis])
    # 如果不允许重复轴,并且存在重复的轴,则抛出 ValueError 异常
    if not allow_duplicate and len(set(axis)) != len(axis):
        if argname:
            raise ValueError('repeated axis in `{}` argument'.format(argname))
        else:
            raise ValueError('repeated axis')
    return axis


def _moveaxis_dispatcher(a, source, destination):
    return (a,)


@array_function_dispatch(_moveaxis_dispatcher)
def moveaxis(a, source, destination):
    """
    Move axes of an array to new positions.

    Other axes remain in their original order.

    .. versionadded:: 1.11.0

    Parameters
    ----------
    a : np.ndarray
        The array whose axes should be reordered.
    source : int or sequence of int
        Original positions of the axes to move. These must be unique.
    destination : int or sequence of int
        Destination positions for each of the original axes. These must also be
        unique.

    Returns
    -------
    result : np.ndarray
        Array with moved axes. This array is a view of the input array.

    See Also
    --------
    transpose : Permute the dimensions of an array.
    swapaxes : Interchange two axes of an array.

    Examples
    --------
    >>> x = np.zeros((3, 4, 5))
    >>> np.moveaxis(x, 0, -1).shape
    (4, 5, 3)
    >>> np.moveaxis(x, -1, 0).shape
    (5, 3, 4)

    These all achieve the same result:
    """
    >>> np.transpose(x).shape
    (5, 4, 3)
    >>> np.swapaxes(x, 0, -1).shape
    (5, 4, 3)
    >>> np.moveaxis(x, [0, 1], [-1, -2]).shape
    (5, 4, 3)
    >>> np.moveaxis(x, [0, 1, 2], [-1, -2, -3]).shape
    (5, 4, 3)

    """
    # 尝试从对象 `a` 中获取 `transpose` 属性,如果不存在则转换为数组再获取
    try:
        transpose = a.transpose
    except AttributeError:
        a = asarray(a)
        transpose = a.transpose

    # 规范化 `source` 和 `destination`,确保它们符合轴的范围
    source = normalize_axis_tuple(source, a.ndim, 'source')
    destination = normalize_axis_tuple(destination, a.ndim, 'destination')
    # 检查 `source` 和 `destination` 是否具有相同数量的元素,否则引发异常
    if len(source) != len(destination):
        raise ValueError('`source` and `destination` arguments must have '
                         'the same number of elements')

    # 创建一个排列 `order`,根据 `source` 和 `destination` 来重新排序轴
    order = [n for n in range(a.ndim) if n not in source]

    # 将 `destination` 和 `source` 组合并按 `destination` 的顺序插入 `order` 中
    for dest, src in sorted(zip(destination, source)):
        order.insert(dest, src)

    # 应用排列 `order` 到 `transpose` 函数,并返回结果
    result = transpose(order)
    return result
# 使用数组函数调度器将函数 _cross_dispatcher 设置为 cross 函数的调度器,负责分发不同的输入情况
@array_function_dispatch(_cross_dispatcher)
def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None):
    """
    Return the cross product of two (arrays of) vectors.

    The cross product of `a` and `b` in :math:`R^3` is a vector perpendicular
    to both `a` and `b`.  If `a` and `b` are arrays of vectors, the vectors
    are defined by the last axis of `a` and `b` by default, and these axes
    can have dimensions 2 or 3.  Where the dimension of either `a` or `b` is
    2, the third component of the input vector is assumed to be zero and the
    cross product calculated accordingly.  In cases where both input vectors
    have dimension 2, the z-component of the cross product is returned.

    Parameters
    ----------
    a : array_like
        Components of the first vector(s).
    b : array_like
        Components of the second vector(s).
    axisa : int, optional
        Axis of `a` that defines the vector(s).  By default, the last axis.
    axisb : int, optional
        Axis of `b` that defines the vector(s).  By default, the last axis.
    axisc : int, optional
        Axis of `c` containing the cross product vector(s).  Ignored if
        both input vectors have dimension 2, as the return is scalar.
        By default, the last axis.
    axis : int, optional
        If defined, the axis of `a`, `b` and `c` that defines the vector(s)
        and cross product(s).  Overrides `axisa`, `axisb` and `axisc`.

    Returns
    -------
    c : ndarray
        Vector cross product(s).

    Raises
    ------
    ValueError
        When the dimension of the vector(s) in `a` and/or `b` does not
        equal 2 or 3.

    See Also
    --------
    inner : Inner product
    outer : Outer product.
    linalg.cross : An Array API compatible variation of ``np.cross``,
                   which accepts (arrays of) 3-element vectors only.
    ix_ : Construct index arrays.

    Notes
    -----
    .. versionadded:: 1.9.0

    Supports full broadcasting of the inputs.

    Dimension-2 input arrays were deprecated in 2.0.0. If you do need this
    functionality, you can use::

        def cross2d(x, y):
            return x[..., 0] * y[..., 1] - x[..., 1] * y[..., 0]

    Examples
    --------
    Vector cross-product.

    >>> x = [1, 2, 3]
    >>> y = [4, 5, 6]
    >>> np.cross(x, y)
    array([-3,  6, -3])

    One vector with dimension 2.

    >>> x = [1, 2]
    >>> y = [4, 5, 6]
    >>> np.cross(x, y)
    array([12, -6, -3])

    Equivalently:

    >>> x = [1, 2, 0]
    >>> y = [4, 5, 6]
    >>> np.cross(x, y)
    array([12, -6, -3])

    Both vectors with dimension 2.

    >>> x = [1,2]
    >>> y = [4,5]
    >>> np.cross(x, y)
    array(-3)

    Multiple vector cross-products. Note that the direction of the cross
    product vector is defined by the *right-hand rule*.

    >>> x = np.array([[1,2,3], [4,5,6]])
    >>> y = np.array([[4,5,6], [1,2,3]])
    """
    # 直接返回输入的两个数组 a 和 b,这是一个默认的实现,实际的计算和处理由 _cross_dispatcher 函数进行分派处理
    return (a, b)
    """
    Calculate the cross product of vectors `a` and `b` in NumPy.

    Parameters:
    ----------
    a, b : array_like
        Input arrays defining vectors.

    axisc : int, optional
        Specify the axis of `c` if provided (default is -1).

    axisa, axisb : int, optional
        Specify the axes of `a` and `b` respectively (default is -1).

    Returns:
    -------
    cp : ndarray
        Cross product of `a` and `b`.

    Raises:
    ------
    ValueError
        - If either `a` or `b` has zero dimension.
        - If the dimensions of `a` or `b` are not compatible for cross product (must be 2 or 3).
    DeprecationWarning
        - If either `a` or `b` are 2-dimensional arrays, as they are deprecated.

    Notes:
    ------
    The function calculates the cross product between vectors `a` and `b` along specified axes.
    If `a` or `b` are 2-dimensional, a warning is issued, recommending the use of 3-dimensional vectors.

    """

    # If `axis` is provided, assign its value to `axisa`, `axisb`, and `axisc`
    if axis is not None:
        axisa, axisb, axisc = (axis,) * 3

    # Ensure `a` and `b` are numpy arrays
    a = asarray(a)
    b = asarray(b)

    # Check if `a` or `b` has zero dimension
    if (a.ndim < 1) or (b.ndim < 1):
        raise ValueError("At least one array has zero dimension")

    # Normalize `axisa` and `axisb` to ensure they are within bounds
    axisa = normalize_axis_index(axisa, a.ndim, msg_prefix='axisa')
    axisb = normalize_axis_index(axisb, b.ndim, msg_prefix='axisb')

    # Move `axisa` and `axisb` to the end of the shape
    a = moveaxis(a, axisa, -1)
    b = moveaxis(b, axisb, -1)

    # Check dimensions are compatible for cross product (must be 2 or 3)
    msg = ("incompatible dimensions for cross product\n"
           "(dimension must be 2 or 3)")
    if a.shape[-1] not in (2, 3) or b.shape[-1] not in (2, 3):
        raise ValueError(msg)

    # Issue deprecation warning if `a` or `b` are 2-dimensional
    if a.shape[-1] == 2 or b.shape[-1] == 2:
        warnings.warn(
            "Arrays of 2-dimensional vectors are deprecated. Use arrays of "
            "3-dimensional vectors instead. (deprecated in NumPy 2.0)",
            DeprecationWarning, stacklevel=2
        )

    # Create the output array `cp` with appropriate shape and dtype
    shape = broadcast(a[..., 0], b[..., 0]).shape
    if a.shape[-1] == 3 or b.shape[-1] == 3:
        shape += (3,)
        axisc = normalize_axis_index(axisc, len(shape), msg_prefix='axisc')
    dtype = promote_types(a.dtype, b.dtype)
    cp = empty(shape, dtype)

    # Recast arrays `a` and `b` as `dtype` for uniform operations
    a = a.astype(dtype)
    b = b.astype(dtype)

    # Create local aliases for readability
    a0 = a[..., 0]
    a1 = a[..., 1]
    if a.shape[-1] == 3:
        a2 = a[..., 2]
    b0 = b[..., 0]
    b1 = b[..., 1]
    if b.shape[-1] == 3:
        b2 = b[..., 2]
    if cp.ndim != 0 and cp.shape[-1] == 3:
        cp0 = cp[..., 0]
        cp1 = cp[..., 1]
        cp2 = cp[..., 2]

    # Perform cross product calculation based on dimensions of `a` and `b`
    if a.shape[-1] == 2:
        if b.shape[-1] == 2:
            # For 2-dimensional `a` and `b`, compute cross product
            multiply(a0, b1, out=cp)
            cp -= a1 * b0
            return cp
        else:
            # For 2-dimensional `a` and 3-dimensional `b`, compute cross product
            multiply(a1, b2, out=cp0)
            multiply(a0, b2, out=cp1)
            negative(cp1, out=cp1)
            multiply(a0, b1, out=cp2)
            cp2 -= a1 * b0
    else:
        # 确保数组 a 的最后一个维度是 3
        assert a.shape[-1] == 3
        if b.shape[-1] == 3:
            # 如果数组 b 的最后一个维度也是 3,则计算叉乘结果
            # cp0 = a1 * b2 - a2 * b1
            # cp1 = a2 * b0 - a0 * b2
            # cp2 = a0 * b1 - a1 * b0
            multiply(a1, b2, out=cp0)
            # 计算临时变量 tmp = a2 * b1
            tmp = array(a2 * b1)
            cp0 -= tmp
            multiply(a2, b0, out=cp1)
            multiply(a0, b2, out=tmp)
            cp1 -= tmp
            multiply(a0, b1, out=cp2)
            multiply(a1, b0, out=tmp)
            cp2 -= tmp
        else:
            # 如果数组 b 的最后一个维度是 2,则按照特定情况计算叉乘结果
            assert b.shape[-1] == 2
            # cp0 = 0 - a2 * b1  (因为 b2 = 0)
            # cp1 = a2 * b0 - 0  (因为 b2 = 0)
            # cp2 = a0 * b1 - a1 * b0
            multiply(a2, b1, out=cp0)
            negative(cp0, out=cp0)
            multiply(a2, b0, out=cp1)
            multiply(a0, b1, out=cp2)
            cp2 -= a1 * b0

    # 将计算结果 cp 的最后一个维度移到指定的轴向 axisc 处并返回
    return moveaxis(cp, -1, axisc)
# 根据系统的字节顺序确定是否为小端序
little_endian = (sys.byteorder == 'little')


@set_module('numpy')
# 将当前函数注册为 numpy 模块的 indices 函数
def indices(dimensions, dtype=int, sparse=False):
    """
    Return an array representing the indices of a grid.

    Compute an array where the subarrays contain index values 0, 1, ...
    varying only along the corresponding axis.

    Parameters
    ----------
    dimensions : sequence of ints
        The shape of the grid.
    dtype : dtype, optional
        Data type of the result.
    sparse : boolean, optional
        Return a sparse representation of the grid instead of a dense
        representation. Default is False.

        .. versionadded:: 1.17

    Returns
    -------
    grid : one ndarray or tuple of ndarrays
        If sparse is False:
            Returns one array of grid indices,
            ``grid.shape = (len(dimensions),) + tuple(dimensions)``.
        If sparse is True:
            Returns a tuple of arrays, with
            ``grid[i].shape = (1, ..., 1, dimensions[i], 1, ..., 1)`` with
            dimensions[i] in the ith place

    See Also
    --------
    mgrid, ogrid, meshgrid

    Notes
    -----
    The output shape in the dense case is obtained by prepending the number
    of dimensions in front of the tuple of dimensions, i.e. if `dimensions`
    is a tuple ``(r0, ..., rN-1)`` of length ``N``, the output shape is
    ``(N, r0, ..., rN-1)``.

    The subarrays ``grid[k]`` contains the N-D array of indices along the
    ``k-th`` axis. Explicitly::

        grid[k, i0, i1, ..., iN-1] = ik

    Examples
    --------
    >>> grid = np.indices((2, 3))
    >>> grid.shape
    (2, 2, 3)
    >>> grid[0]        # row indices
    array([[0, 0, 0],
           [1, 1, 1]])
    >>> grid[1]        # column indices
    array([[0, 1, 2],
           [0, 1, 2]])

    The indices can be used as an index into an array.

    >>> x = np.arange(20).reshape(5, 4)
    >>> row, col = np.indices((2, 3))
    >>> x[row, col]
    array([[0, 1, 2],
           [4, 5, 6]])

    Note that it would be more straightforward in the above example to
    extract the required elements directly with ``x[:2, :3]``.

    If sparse is set to true, the grid will be returned in a sparse
    representation.

    >>> i, j = np.indices((2, 3), sparse=True)
    >>> i.shape
    (2, 1)
    >>> j.shape
    (1, 3)
    >>> i        # row indices
    array([[0],
           [1]])
    >>> j        # column indices
    array([[0, 1, 2]])

    """
    dimensions = tuple(dimensions)
    N = len(dimensions)
    shape = (1,)*N
    # 根据 sparse 参数选择返回稠密或稀疏表示的结果数组
    if sparse:
        res = tuple()
    else:
        res = empty((N,)+dimensions, dtype=dtype)
    for i, dim in enumerate(dimensions):
        # 创建包含索引值的数组,每个子数组沿相应轴变化
        idx = arange(dim, dtype=dtype).reshape(
            shape[:i] + (dim,) + shape[i+1:]
        )
        if sparse:
            res = res + (idx,)
        else:
            res[i] = idx
    # 返回结果数组或元组
    return res


@set_array_function_like_doc
@set_module('numpy')
def fromfunction(function, shape, *, dtype=float, like=None, **kwargs):
    """
    Construct an array by executing a function over each coordinate.

    The resulting array therefore has a value ``fn(x, y, z)`` at
    coordinate ``(x, y, z)``.

    Parameters
    ----------
    function : callable
        The function is called with N parameters, where N is the rank of
        `shape`.  Each parameter represents the coordinates of the array
        varying along a specific axis.  For example, if `shape`
        were ``(2, 2)``, then the parameters would be
        ``array([[0, 0], [1, 1]])`` and ``array([[0, 1], [0, 1]])``
    shape : (N,) tuple of ints
        Shape of the output array, which also determines the shape of
        the coordinate arrays passed to `function`.
    dtype : data-type, optional
        Data-type of the coordinate arrays passed to `function`.
        By default, `dtype` is float.
    ${ARRAY_FUNCTION_LIKE}

        .. versionadded:: 1.20.0

    Returns
    -------
    fromfunction : any
        The result of the call to `function` is passed back directly.
        Therefore the shape of `fromfunction` is completely determined by
        `function`.  If `function` returns a scalar value, the shape of
        `fromfunction` would not match the `shape` parameter.

    See Also
    --------
    indices, meshgrid

    Notes
    -----
    Keywords other than `dtype` and `like` are passed to `function`.

    Examples
    --------
    >>> np.fromfunction(lambda i, j: i, (2, 2), dtype=float)
    array([[0., 0.],
           [1., 1.]])

    >>> np.fromfunction(lambda i, j: j, (2, 2), dtype=float)
    array([[0., 1.],
           [0., 1.]])

    >>> np.fromfunction(lambda i, j: i == j, (3, 3), dtype=int)
    array([[ True, False, False],
           [False,  True, False],
           [False, False,  True]])

    >>> np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int)
    array([[0, 1, 2],
           [1, 2, 3],
           [2, 3, 4]])

    """
    # 如果给定了 like 参数,则调用 _fromfunction_with_like 函数处理
    if like is not None:
        return _fromfunction_with_like(
                like, function, shape, dtype=dtype, **kwargs)

    # 根据 shape 和 dtype 参数生成坐标数组 args
    args = indices(shape, dtype=dtype)
    # 调用 function 函数,并传入生成的坐标数组 args 和其他关键字参数 kwargs
    return function(*args, **kwargs)
# 将 `fromfunction` 函数注册为具有数组功能分派的函数,并赋值给 `_fromfunction_with_like`
_fromfunction_with_like = array_function_dispatch()(fromfunction)

# 从给定的缓冲区 `buf` 中创建一个数组,指定数据类型 `dtype`、形状 `shape` 和存储顺序 `order`,
# 然后将其重新塑形为指定形状和顺序的数组
def _frombuffer(buf, dtype, shape, order):
    return frombuffer(buf, dtype=dtype).reshape(shape, order=order)

# 将当前函数标记为属于 'numpy' 模块的函数
@set_module('numpy')
def isscalar(element):
    """
    Returns True if the type of `element` is a scalar type.

    Parameters
    ----------
    element : any
        Input argument, can be of any type and shape.

    Returns
    -------
    val : bool
        True if `element` is a scalar type, False if it is not.

    See Also
    --------
    ndim : Get the number of dimensions of an array

    Notes
    -----
    If you need a stricter way to identify a *numerical* scalar, use
    ``isinstance(x, numbers.Number)``, as that returns ``False`` for most
    non-numerical elements such as strings.

    In most cases ``np.ndim(x) == 0`` should be used instead of this function,
    as that will also return true for 0d arrays. This is how numpy overloads
    functions in the style of the ``dx`` arguments to `gradient` and
    the ``bins`` argument to `histogram`. Some key differences:

    +------------------------------------+---------------+-------------------+
    | x                                  |``isscalar(x)``|``np.ndim(x) == 0``|
    +====================================+===============+===================+
    | PEP 3141 numeric objects           | ``True``      | ``True``          |
    | (including builtins)               |               |                   |
    +------------------------------------+---------------+-------------------+
    | builtin string and buffer objects  | ``True``      | ``True``          |
    +------------------------------------+---------------+-------------------+
    | other builtin objects, like        | ``False``     | ``True``          |
    | `pathlib.Path`, `Exception`,       |               |                   |
    | the result of `re.compile`         |               |                   |
    +------------------------------------+---------------+-------------------+
    | third-party objects like           | ``False``     | ``True``          |
    | `matplotlib.figure.Figure`         |               |                   |
    +------------------------------------+---------------+-------------------+
    | zero-dimensional numpy arrays      | ``False``     | ``True``          |
    +------------------------------------+---------------+-------------------+
    | other numpy arrays                 | ``False``     | ``False``         |
    +------------------------------------+---------------+-------------------+
    | `list`, `tuple`, and other         | ``False``     | ``False``         |
    | sequence objects                   |               |                   |
    +------------------------------------+---------------+-------------------+

    Examples
    --------
    >>> np.isscalar(3.1)
    True
    >>> np.isscalar(np.array(3.1))
    False
    >>> np.isscalar([3.1])
    False
    >>> np.isscalar(False)
    True
    """
    # 检查给定元素是否是标量(scalar)
    >>> np.isscalar('numpy')
    # 返回 True,因为字符串 'numpy' 是一个标量
    
    NumPy 支持 PEP 3141 标量数值:
    
    # 导入 Fraction 类
    >>> from fractions import Fraction
    # 检查 Fraction(5, 17) 是否是标量
    >>> np.isscalar(Fraction(5, 17))
    # 返回 True,因为 Fraction(5, 17) 是一个标量
    
    # 导入 Number 类
    >>> from numbers import Number
    # 检查 Number() 是否是标量
    >>> np.isscalar(Number())
    # 返回 True,因为 Number() 是一个标量
    
    """
    返回一个布尔值,判断 element 是否是标量类型 generic 中的实例,
    或者 element 的类型是否在 ScalarType 中,
    或者 element 是否是 numbers.Number 的实例。
    """
    return (isinstance(element, generic)
            or type(element) in ScalarType
            or isinstance(element, numbers.Number))
@set_module('numpy')
# 设置模块为 'numpy',这是一个装饰器函数,用于在函数定义时设置模块信息

def binary_repr(num, width=None):
    """
    Return the binary representation of the input number as a string.

    For negative numbers, if width is not given, a minus sign is added to the
    front. If width is given, the two's complement of the number is
    returned, with respect to that width.

    In a two's-complement system negative numbers are represented by the two's
    complement of the absolute value. This is the most common method of
    representing signed integers on computers [1]_. A N-bit two's-complement
    system can represent every integer in the range
    :math:`-2^{N-1}` to :math:`+2^{N-1}-1`.

    Parameters
    ----------
    num : int
        Only an integer decimal number can be used.
    width : int, optional
        The length of the returned string if `num` is positive, or the length
        of the two's complement if `num` is negative, provided that `width` is
        at least a sufficient number of bits for `num` to be represented in
        the designated form. If the `width` value is insufficient, an error is
        raised.

    Returns
    -------
    bin : str
        Binary representation of `num` or two's complement of `num`.

    See Also
    --------
    base_repr: Return a string representation of a number in the given base
               system.
    bin: Python's built-in binary representation generator of an integer.

    Notes
    -----
    `binary_repr` is equivalent to using `base_repr` with base 2, but about 25x
    faster.

    References
    ----------
    .. [1] Wikipedia, "Two's complement",
        https://en.wikipedia.org/wiki/Two's_complement

    Examples
    --------
    >>> np.binary_repr(3)
    '11'
    >>> np.binary_repr(-3)
    '-11'
    >>> np.binary_repr(3, width=4)
    '0011'

    The two's complement is returned when the input number is negative and
    width is specified:

    >>> np.binary_repr(-3, width=3)
    '101'
    >>> np.binary_repr(-3, width=5)
    '11101'

    """
    # 内部函数,用于检查指定的宽度是否足够容纳二进制表示,如果不足则引发 ValueError 异常
    def err_if_insufficient(width, binwidth):
        if width is not None and width < binwidth:
            raise ValueError(
                f"Insufficient bit {width=} provided for {binwidth=}"
            )

    # 确保 num 是一个 Python 整数,避免溢出或不必要的浮点转换
    num = operator.index(num)

    if num == 0:
        return '0' * (width or 1)
    elif num > 0:
        # 获取 num 的二进制表示,并移除前缀 '0b'
        binary = bin(num)[2:]
        binwidth = len(binary)  # 计算二进制字符串的长度
        # 计算输出字符串的宽度,如果指定了 width,则取二者的最大值
        outwidth = (binwidth if width is None
                    else builtins.max(binwidth, width))
        # 检查宽度是否足够,如果不足则引发异常
        err_if_insufficient(width, binwidth)
        # 左侧填充二进制字符串,使其达到指定的宽度
        return binary.zfill(outwidth)
    else:
        if width is None:
            # 如果宽度未指定,生成补码表示的负数的二进制字符串
            return '-' + bin(-num)[2:]
        else:
            # 计算补码表示的负数的二进制字符串的长度
            poswidth = len(bin(-num)[2:])

            # 查看 GitHub 问题 #8679:移除边界处数字的额外位数
            if 2**(poswidth - 1) == -num:
                # 如果数字处于边界,减少位数
                poswidth -= 1

            # 计算补码表示的数值
            twocomp = 2**(poswidth + 1) + num
            binary = bin(twocomp)[2:]  # 转换为二进制字符串
            binwidth = len(binary)  # 计算二进制字符串的长度

            # 确定输出的宽度
            outwidth = builtins.max(binwidth, width)
            # 如果宽度不足,则引发错误
            err_if_insufficient(width, binwidth)
            # 返回二进制字符串,左侧用 '1' 填充至指定宽度
            return '1' * (outwidth - binwidth) + binary
# 将当前模块设置为'numpy'
@set_module('numpy')
# 定义函数base_repr,用于将整数number转换为指定base进制的字符串表示形式,可指定左侧填充的零数padding
def base_repr(number, base=2, padding=0):
    """
    Return a string representation of a number in the given base system.

    Parameters
    ----------
    number : int
        The value to convert. Positive and negative values are handled.
    base : int, optional
        Convert `number` to the `base` number system. The valid range is 2-36,
        the default value is 2.
    padding : int, optional
        Number of zeros padded on the left. Default is 0 (no padding).

    Returns
    -------
    out : str
        String representation of `number` in `base` system.

    See Also
    --------
    binary_repr : Faster version of `base_repr` for base 2.

    Examples
    --------
    >>> np.base_repr(5)
    '101'
    >>> np.base_repr(6, 5)
    '11'
    >>> np.base_repr(7, base=5, padding=3)
    '00012'

    >>> np.base_repr(10, base=16)
    'A'
    >>> np.base_repr(32, base=16)
    '20'

    """
    # 定义所有可能的数字字符,用于各进制的表示
    digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    # 如果指定的进制超过了digits中的字符数,抛出异常
    if base > len(digits):
        raise ValueError("Bases greater than 36 not handled in base_repr.")
    # 如果指定的进制小于2,抛出异常
    elif base < 2:
        raise ValueError("Bases less than 2 not handled in base_repr.")

    # 取number的绝对值
    num = abs(int(number))
    res = []
    # 将number转换为base进制的字符串表示形式
    while num:
        res.append(digits[num % base])
        num //= base
    # 如果需要填充左侧零,则添加
    if padding:
        res.append('0' * padding)
    # 如果number为负数,则在结果前加上负号
    if number < 0:
        res.append('-')
    # 将列表res反转并连接成字符串,作为结果返回
    return ''.join(reversed(res or '0'))


# 下面这些都基本上是缩写
# 这些可能最终会出现在一个特殊的缩写模块中


# 定义私有函数_maketup,根据描述符descr和值val创建元组
def _maketup(descr, val):
    # 根据描述符创建数据类型对象dt
    dt = dtype(descr)
    # 如果dt没有字段,则直接返回val
    fields = dt.fields
    if fields is None:
        return val
    else:
        # 否则,递归调用_maketup,为每个字段创建元组,最后返回元组形式的结果
        res = [_maketup(fields[name][0], val) for name in dt.names]
        return tuple(res)


# 将当前函数设置为数组函数的文档模式
@set_array_function_like_doc
# 将当前模块设置为'numpy'
@set_module('numpy')
# 定义函数identity,返回一个单位矩阵数组
def identity(n, dtype=None, *, like=None):
    """
    Return the identity array.

    The identity array is a square array with ones on
    the main diagonal.

    Parameters
    ----------
    n : int
        Number of rows (and columns) in `n` x `n` output.
    dtype : data-type, optional
        Data-type of the output.  Defaults to ``float``.
    ${ARRAY_FUNCTION_LIKE}

        .. versionadded:: 1.20.0

    Returns
    -------
    out : ndarray
        `n` x `n` array with its main diagonal set to one,
        and all other elements 0.

    Examples
    --------
    >>> np.identity(3)
    array([[1.,  0.,  0.],
           [0.,  1.,  0.],
           [0.,  0.,  1.]])

    """
    # 如果指定了like参数,调用_identity_with_like函数进行处理
    if like is not None:
        return _identity_with_like(like, n, dtype=dtype)

    # 从numpy模块导入eye函数,返回一个单位矩阵数组
    from numpy import eye
    return eye(n, dtype=dtype, like=like)


# 将_identity_with_like函数通过array_function_dispatch装饰器进行分发
_identity_with_like = array_function_dispatch()(identity)


# 定义_allclose_dispatcher函数,返回传入的a、b、rtol、atol参数元组
def _allclose_dispatcher(a, b, rtol=None, atol=None, equal_nan=None):
    return (a, b, rtol, atol)


# 将_allclose_dispatcher函数通过array_function_dispatch装饰器进行分发
@array_function_dispatch(_allclose_dispatcher)
# 定义函数allclose,用于比较两个数组的元素是否在公差范围内相等
def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
    """
    # 比较两个数组是否在容差范围内逐元素相等。
    
    # 容差值为正数,通常是非常小的数。相对差异 (`rtol` * abs(`b`)) 和绝对差异 `atol` 被加在一起,用来与 `a` 和 `b` 的绝对差异比较。
    
    # .. warning:: 默认的 `atol` 不适用于比较远小于一的数值(参见注释)。
    
    # 如果NaN在同一位置且 ``equal_nan=True``,则被视为相等。如果Inf在同一位置且在两个数组中的符号相同,则被视为相等。
    
    # 参数
    # ----------
    # a, b : array_like
    #     要比较的输入数组。
    # rtol : array_like
    #     相对容差参数(见注释)。
    # atol : array_like
    #     绝对容差参数(见注释)。
    # equal_nan : bool
    #     是否将NaN视为相等。如果为True,则 `a` 中的NaN将与 `b` 中的NaN在输出数组中被视为相等。
    
    #     .. versionadded:: 1.10.0
    
    # 返回
    # -------
    # allclose : bool
    #     如果两个数组在给定的容差内相等,则返回True;否则返回False。
    
    # 参见
    # --------
    # isclose, all, any, equal
    
    # 注释
    # -----
    # 如果以下方程逐元素为True,则 `allclose` 返回True。::
    
    #     absolute(a - b) <= (atol + rtol * absolute(b))
    
    # 上述方程在 `a` 和 `b` 中不对称,因此在某些罕见情况下,``allclose(a, b)`` 可能与 ``allclose(b, a)`` 不同。
    
    # 当参考值 `b` 的幅度小于一时,默认值 `atol` 是不合适的。例如, ``a = 1e-9`` 和 ``b = 2e-9`` 可能不应被视为 "接近",但是 ``allclose(1e-9, 2e-9)`` 在默认设置下返回True。请确保根据具体情况选择 `atol`,特别是用于定义 `a` 中非零值与 `b` 中非常小或零值之间的阈值。
    
    # `a` 和 `b` 的比较使用标准的广播方式,这意味着 `a` 和 `b` 不需要具有相同的形状才能使 ``allclose(a, b)`` 评估为True。对于 `equal` 也是如此,但对于 `array_equal` 则不是。
    
    # `allclose` 对于非数值数据类型未定义。
    # 对于此目的,`bool` 被视为数值数据类型。
    
    # 示例
    # --------
    # >>> np.allclose([1e10,1e-7], [1.00001e10,1e-8])
    # False
    # >>> np.allclose([1e10,1e-8], [1.00001e10,1e-9])
    # True
    # >>> np.allclose([1e10,1e-8], [1.0001e10,1e-9])
    # False
    # >>> np.allclose([1.0, np.nan], [1.0, np.nan])
    # False
    # >>> np.allclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
    # True
# 根据输入参数创建一个调度器,用于分派到合适的 isclose 函数
def _isclose_dispatcher(a, b, rtol=None, atol=None, equal_nan=None):
    # 返回输入参数元组,用于后续的分派
    return (a, b, rtol, atol)

# 使用 array_function_dispatch 装饰器,将 _isclose_dispatcher 函数作为分派器,用于 isclose 函数
@array_function_dispatch(_isclose_dispatcher)
def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
    """
    Returns a boolean array where two arrays are element-wise equal within a
    tolerance.

    The tolerance values are positive, typically very small numbers.  The
    relative difference (`rtol` * abs(`b`)) and the absolute difference
    `atol` are added together to compare against the absolute difference
    between `a` and `b`.

    .. warning:: The default `atol` is not appropriate for comparing numbers
                 with magnitudes much smaller than one (see Notes).

    Parameters
    ----------
    a, b : array_like
        Input arrays to compare.
    rtol : array_like
        The relative tolerance parameter (see Notes).
    atol : array_like
        The absolute tolerance parameter (see Notes).
    equal_nan : bool
        Whether to compare NaN's as equal.  If True, NaN's in `a` will be
        considered equal to NaN's in `b` in the output array.

    Returns
    -------
    y : array_like
        Returns a boolean array of where `a` and `b` are equal within the
        given tolerance. If both `a` and `b` are scalars, returns a single
        boolean value.

    See Also
    --------
    allclose
    math.isclose

    Notes
    -----
    .. versionadded:: 1.7.0

    For finite values, isclose uses the following equation to test whether
    two floating point values are equivalent.::

     absolute(a - b) <= (atol + rtol * absolute(b))

    Unlike the built-in `math.isclose`, the above equation is not symmetric
    in `a` and `b` -- it assumes `b` is the reference value -- so that
    `isclose(a, b)` might be different from `isclose(b, a)`.

    The default value of `atol` is not appropriate when the reference value
    `b` has magnitude smaller than one. For example, it is unlikely that
    ``a = 1e-9`` and ``b = 2e-9`` should be considered "close", yet
    ``isclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure
    to select `atol` for the use case at hand, especially for defining the
    threshold below which a non-zero value in `a` will be considered "close"
    to a very small or zero value in `b`.

    `isclose` is not defined for non-numeric data types.
    :class:`bool` is considered a numeric data-type for this purpose.

    Examples
    --------
    >>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
    array([ True, False])
    >>> np.isclose([1e10,1e-8], [1.00001e10,1e-9])
    array([ True, True])
    >>> np.isclose([1e10,1e-8], [1.0001e10,1e-9])
    array([False,  True])
    >>> np.isclose([1.0, np.nan], [1.0, np.nan])
    array([ True, False])
    >>> np.isclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
    array([ True, True])
    >>> np.isclose([1e-8, 1e-7], [0.0, 0.0])
    array([ True, False])
    >>> np.isclose([1e-100, 1e-7], [0.0, 0.0], atol=0.0)
    array([False, False])
    """
    # 使用 NumPy 的 isclose 函数比较两个数组的元素是否在误差范围内相等
    >>> np.isclose([1e-10, 1e-10], [1e-20, 0.0])
    array([ True,  True])
    
    # 使用 NumPy 的 isclose 函数比较两个数组的元素是否在指定的绝对误差范围内相等
    >>> np.isclose([1e-10, 1e-10], [1e-20, 0.999999e-10], atol=0.0)
    array([False,  True])
    """
    # 将除了 Python 标量之外的对象转换为数组
    x, y, atol, rtol = (
        a if isinstance(a, (int, float, complex)) else asanyarray(a)
        for a in (a, b, atol, rtol))
    
    # 确保 y 是一个非精确类型,以避免在 abs(MIN_INT) 上出现错误行为
    # 这将导致稍后将 x 转换为该类型。同时,确保允许子类(例如 numpy.ma)
    # 注意:我们明确允许 timedelta,这在过去有效。这可能会被弃用。另请参见 gh-18286。
    # timedelta 在 `atol` 是整数或 timedelta 时有效。
    # 尽管如此,默认的公差可能不太有用
    if (dtype := getattr(y, "dtype", None)) is not None and dtype.kind != "m":
        dt = multiarray.result_type(y, 1.)
        y = asanyarray(y, dtype=dt)
    elif isinstance(y, int):
        y = float(y)
    
    # 使用 errstate 来忽略无效值的警告,并通过 _no_nep50_warning 确保不显示 NEP 50 的警告
    with errstate(invalid='ignore'), _no_nep50_warning():
        # 计算两数组之间的相等性
        result = (less_equal(abs(x-y), atol + rtol * abs(y))
                  & isfinite(y)
                  | (x == y))
        # 如果需要,处理 NaN 的情况
        if equal_nan:
            result |= isnan(x) & isnan(y)
    
    # 返回扁平化的零维数组结果作为标量
    return result[()]
def _array_equal_dispatcher(a1, a2, equal_nan=None):
    # 将输入的两个数组作为一个元组返回,用于数组相等性判断的调度器
    return (a1, a2)


_no_nan_types = {
    # 不包含可以容纳 NaN 值的数据类型集合,这些类型不支持 NaN 比较
    # 应该使用 np.dtype.BoolDType,但在写作时未通过重新加载测试
    type(dtype(nt.bool)),
    type(dtype(nt.int8)),
    type(dtype(nt.int16)),
    type(dtype(nt.int32)),
    type(dtype(nt.int64)),
}


def _dtype_cannot_hold_nan(dtype):
    # 判断给定的数据类型是否在 _no_nan_types 集合中,即是否不能容纳 NaN 值
    return type(dtype) in _no_nan_types


@array_function_dispatch(_array_equal_dispatcher)
def array_equal(a1, a2, equal_nan=False):
    """
    如果两个数组具有相同的形状和元素,则返回 True,否则返回 False。

    Parameters
    ----------
    a1, a2 : array_like
        输入数组。
    equal_nan : bool
        是否将 NaN 视为相等。如果 a1 和 a2 的 dtype 是复数,则如果给定值的实部或虚部为 NaN,则视为相等。

        .. versionadded:: 1.19.0

    Returns
    -------
    b : bool
        如果数组相等则返回 True。

    See Also
    --------
    allclose: 如果两个数组在容差范围内逐元素相等,则返回 True。
    array_equiv: 如果输入数组在形状上一致且所有元素相等,则返回 True。

    Examples
    --------
    >>> np.array_equal([1, 2], [1, 2])
    True
    >>> np.array_equal(np.array([1, 2]), np.array([1, 2]))
    True
    >>> np.array_equal([1, 2], [1, 2, 3])
    False
    >>> np.array_equal([1, 2], [1, 4])
    False
    >>> a = np.array([1, np.nan])
    >>> np.array_equal(a, a)
    False
    >>> np.array_equal(a, a, equal_nan=True)
    True

    当 equal_nan 为 True 时,如果复数值的组成部分为 NaN,则认为它们是相等的。

    >>> a = np.array([1 + 1j])
    >>> b = a.copy()
    >>> a.real = np.nan
    >>> b.imag = np.nan
    >>> np.array_equal(a, b, equal_nan=True)
    True
    """
    try:
        a1, a2 = asarray(a1), asarray(a2)
    except Exception:
        return False
    if a1.shape != a2.shape:
        return False
    if not equal_nan:
        return builtins.bool((a1 == a2).all())
    cannot_have_nan = (_dtype_cannot_hold_nan(a1.dtype)
                       and _dtype_cannot_hold_nan(a2.dtype))
    if cannot_have_nan:
        if a1 is a2:
            return True
        return builtins.bool((a1 == a2).all())

    if a1 is a2:
        # NaN 将被视为相等,因此数组将与自身比较相等。
        return True
    # 如果 equal_nan 为 True,则处理 NaN 值
    a1nan, a2nan = isnan(a1), isnan(a2)
    # NaN 出现在不同位置
    if not (a1nan == a2nan).all():
        return False
    # 到这一步,a1、a2 和掩码的形状保证一致
    return builtins.bool((a1[~a1nan] == a2[~a1nan]).all())


def _array_equiv_dispatcher(a1, a2):
    # 将输入的两个数组作为一个元组返回,用于数组等价性判断的调度器
    return (a1, a2)


@array_function_dispatch(_array_equiv_dispatcher)
def array_equiv(a1, a2):
    """
    Returns True if input arrays are shape consistent and all elements equal.

    Shape consistent means they are either the same shape, or one input array
    can be broadcasted to create the same shape as the other one.

    Parameters
    ----------
    a1, a2 : array_like
        Input arrays.

    Returns
    -------
    out : bool
        True if equivalent, False otherwise.

    Examples
    --------
    >>> np.array_equiv([1, 2], [1, 2])
    True
    >>> np.array_equiv([1, 2], [1, 3])
    False

    Showing the shape equivalence:

    >>> np.array_equiv([1, 2], [[1, 2], [1, 2]])
    True
    >>> np.array_equiv([1, 2], [[1, 2, 1, 2], [1, 2, 1, 2]])
    False

    >>> np.array_equiv([1, 2], [[1, 2], [1, 3]])
    False

    """
    # 尝试将输入的 a1 和 a2 转换为数组
    try:
        a1, a2 = asarray(a1), asarray(a2)
    except Exception:
        # 转换失败则返回 False
        return False
    # 尝试使用广播来匹配数组的形状
    try:
        multiarray.broadcast(a1, a2)
    except Exception:
        # 广播失败则返回 False
        return False

    # 检查数组 a1 和 a2 的所有元素是否完全相等,返回比较结果
    return builtins.bool((a1 == a2).all())
# 定义一个函数 _astype_dispatcher,用于类型分发,接收参数 x, dtype 和可选的 copy
def _astype_dispatcher(x, dtype, /, *, copy=None):
    # 返回一个元组,包含参数 x 和 dtype
    return (x, dtype)


# 使用 array_function_dispatch 装饰器将 _astype_dispatcher 函数注册为 astype 函数的分发器
@array_function_dispatch(_astype_dispatcher)
# 定义 astype 函数,用于将数组复制到指定的数据类型
def astype(x, dtype, /, *, copy = True):
    """
    Copies an array to a specified data type.

    This function is an Array API compatible alternative to
    `numpy.ndarray.astype`.

    Parameters
    ----------
    x : ndarray
        Input NumPy array to cast. ``array_likes`` are explicitly not
        supported here.
    dtype : dtype
        Data type of the result.
    copy : bool, optional
        Specifies whether to copy an array when the specified dtype matches
        the data type of the input array ``x``. If ``True``, a newly allocated
        array must always be returned. If ``False`` and the specified dtype
        matches the data type of the input array, the input array must be
        returned; otherwise, a newly allocated array must be returned.
        Defaults to ``True``.

    Returns
    -------
    out : ndarray
        An array having the specified data type.

    See Also
    --------
    ndarray.astype

    Examples
    --------
    >>> arr = np.array([1, 2, 3]); arr
    array([1, 2, 3])
    >>> np.astype(arr, np.float64)
    array([1., 2., 3.])

    Non-copy case:

    >>> arr = np.array([1, 2, 3])
    >>> arr_noncpy = np.astype(arr, arr.dtype, copy=False)
    >>> np.shares_memory(arr, arr_noncpy)
    True

    """
    # 如果输入不是 NumPy 数组,则抛出 TypeError 异常
    if not isinstance(x, np.ndarray):
        raise TypeError(
            f"Input should be a NumPy array. It is a {type(x)} instead."
        )
    # 调用输入数组 x 的 astype 方法,将其转换为指定的数据类型 dtype,并根据 copy 参数决定是否复制数组
    return x.astype(dtype, copy=copy)


# 定义 inf 为正无穷大常量 PINF
inf = PINF
# 定义 nan 为 NaN 常量 NAN
nan = NAN
# 定义 False_ 为布尔类型 False 的别名
False_ = nt.bool(False)
# 定义 True_ 为布尔类型 True 的别名
True_ = nt.bool(True)


# 定义 extend_all 函数,用于向 __all__ 中扩展模块的所有内容
def extend_all(module):
    # 获取当前 __all__ 的内容,并转换为集合
    existing = set(__all__)
    # 获取给定模块的 __all__ 属性
    mall = getattr(module, '__all__')
    # 遍历模块的 __all__ 中的每个元素
    for a in mall:
        # 如果元素不在现有的 __all__ 中,则将其添加到 __all__ 中
        if a not in existing:
            __all__.append(a)


# 导入 umath 模块中的所有内容
from .umath import *
# 导入 numerictypes 模块中的所有内容
from .numerictypes import *
# 导入 fromnumeric 模块
from . import fromnumeric
# 从 fromnumeric 模块中导入所有内容
from .fromnumeric import *
# 导入 arrayprint 模块
from . import arrayprint
# 从 arrayprint 模块中导入所有内容
from .arrayprint import *
# 导入 _asarray 模块
from . import _asarray
# 从 _asarray 模块中导入所有内容
from ._asarray import *
# 导入 _ufunc_config 模块
from . import _ufunc_config
# 从 _ufunc_config 模块中导入所有内容
from ._ufunc_config import *

# 扩展 __all__ 列表以包含来自不同模块的内容
extend_all(fromnumeric)
extend_all(umath)
extend_all(numerictypes)
extend_all(arrayprint)
extend_all(_asarray)
extend_all(_ufunc_config)

.\numpy\numpy\_core\numeric.pyi

# 从 collections.abc 导入 Callable 和 Sequence 类型
from collections.abc import Callable, Sequence
# 导入 typing 模块的多个类型和装饰器
from typing import (
    Any,                # 任意类型
    overload,           # 函数重载装饰器
    TypeVar,            # 泛型类型变量
    Literal as L,       # 字面值类型别名
    SupportsAbs,        # 支持绝对值的类型
    SupportsIndex,      # 支持索引的类型
    NoReturn,           # 函数无返回值
)

# 根据系统版本导入不同的类型
if sys.version_info >= (3, 10):
    from typing import TypeGuard   # 类型守卫(Python 3.10 及以上版本)
else:
    from typing_extensions import TypeGuard  # 类型守卫(Python 3.10 以下版本的扩展)

import numpy as np                 # 导入 numpy 库
from numpy import (                # 从 numpy 导入多个子模块和类
    ComplexWarning as ComplexWarning,   # 复数警告类别
    generic,                        # 泛型类型
    unsignedinteger,                # 无符号整数类型
    signedinteger,                  # 有符号整数类型
    floating,                       # 浮点数类型
    complexfloating,                # 复数类型
    int_,                           # 整数类型
    intp,                           # 整数指针类型
    float64,                        # 双精度浮点数类型
    timedelta64,                    # 时间增量类型
    object_,                        # 对象类型
    _OrderKACF,                     # 数组排序类型(知识缺失)
    _OrderCF,                       # 数组排序类型(知识缺失)
)

from numpy._typing import (         # 导入 numpy 的类型注解
    ArrayLike,                      # 类数组类型
    NDArray,                        # 多维数组类型
    DTypeLike,                      # 数据类型或类似类型
    _ShapeLike,                     # 形状或类似类型
    _DTypeLike,                     # 数据类型或类似类型
    _ArrayLike,                     # 类数组类型
    _SupportsArrayFunc,             # 支持数组函数的类型
    _ScalarLike_co,                 # 协变标量类型
    _ArrayLikeBool_co,              # 协变布尔数组类型
    _ArrayLikeUInt_co,              # 协变无符号整数数组类型
    _ArrayLikeInt_co,               # 协变有符号整数数组类型
    _ArrayLikeFloat_co,             # 协变浮点数数组类型
    _ArrayLikeComplex_co,           # 协变复数数组类型
    _ArrayLikeTD64_co,              # 协变时间增量数组类型
    _ArrayLikeObject_co,            # 协变对象数组类型
    _ArrayLikeUnknown,              # 未知协变数组类型
)

_T = TypeVar("_T")                  # 定义泛型类型变量 _T
_SCT = TypeVar("_SCT", bound=generic)   # 定义泛型类型变量 _SCT,限制为泛型类型
_ArrayType = TypeVar("_ArrayType", bound=NDArray[Any])   # 定义泛型类型变量 _ArrayType,限制为任意类型的 NDArray

_CorrelateMode = L["valid", "same", "full"]    # 定义字面值类型别名 _CorrelateMode,包含三个字符串元素

__all__: list[str] = []             # 定义模块的公开接口列表,初始为空列表

@overload
def zeros_like(
    a: _ArrayType,                  # 参数 a 的类型为 _ArrayType
    dtype: None = ...,              # dtype 参数,默认为 None
    order: _OrderKACF = ...,        # order 参数,默认为 _OrderKACF 类型
    subok: L[True] = ...,           # subok 参数,默认为字面值类型 True
    shape: None = ...,              # shape 参数,默认为 None
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
) -> _ArrayType: ...                # 返回类型为 _ArrayType 的函数重载

@overload
def zeros_like(
    a: _ArrayLike[_SCT],            # 参数 a 的类型为 _ArrayLike[_SCT]
    dtype: None = ...,              # dtype 参数,默认为 None
    order: _OrderKACF = ...,        # order 参数,默认为 _OrderKACF 类型
    subok: bool = ...,              # subok 参数,默认为布尔类型
    shape: None | _ShapeLike = ..., # shape 参数,默认为 None 或 _ShapeLike 类型
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
) -> NDArray[_SCT]: ...             # 返回类型为 NDArray[_SCT] 的函数重载

@overload
def zeros_like(
    a: object,                      # 参数 a 的类型为 object
    dtype: None = ...,              # dtype 参数,默认为 None
    order: _OrderKACF = ...,        # order 参数,默认为 _OrderKACF 类型
    subok: bool = ...,              # subok 参数,默认为布尔类型
    shape: None | _ShapeLike = ..., # shape 参数,默认为 None 或 _ShapeLike 类型
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
) -> NDArray[Any]: ...              # 返回类型为 NDArray[Any] 的函数重载

@overload
def zeros_like(
    a: Any,                         # 参数 a 的类型为 Any
    dtype: _DTypeLike[_SCT],        # dtype 参数的类型为 _DTypeLike[_SCT]
    order: _OrderKACF = ...,        # order 参数,默认为 _OrderKACF 类型
    subok: bool = ...,              # subok 参数,默认为布尔类型
    shape: None | _ShapeLike = ..., # shape 参数,默认为 None 或 _ShapeLike 类型
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
) -> NDArray[_SCT]: ...             # 返回类型为 NDArray[_SCT] 的函数重载

@overload
def zeros_like(
    a: Any,                         # 参数 a 的类型为 Any
    dtype: DTypeLike,               # dtype 参数的类型为 DTypeLike
    order: _OrderKACF = ...,        # order 参数,默认为 _OrderKACF 类型
    subok: bool = ...,              # subok 参数,默认为布尔类型
    shape: None | _ShapeLike = ..., # shape 参数,默认为 None 或 _ShapeLike 类型
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
) -> NDArray[Any]: ...              # 返回类型为 NDArray[Any] 的函数重载

@overload
def ones(
    shape: _ShapeLike,              # 参数 shape 的类型为 _ShapeLike
    dtype: None = ...,              # dtype 参数,默认为 None
    order: _OrderCF = ...,          # order 参数,默认为 _OrderCF 类型
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
    like: _SupportsArrayFunc = ..., # like 参数,默认为 _SupportsArrayFunc 类型
) -> NDArray[float64]: ...          # 返回类型为 NDArray[float64] 的函数重载

@overload
def ones(
    shape: _ShapeLike,              # 参数 shape 的类型为 _ShapeLike
    dtype: _DTypeLike[_SCT],        # dtype 参数的类型为 _DTypeLike[_SCT]
    order: _OrderCF = ...,          # order 参数,默认为 _OrderCF 类型
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
    like: _SupportsArrayFunc = ..., # like 参数,默认为 _SupportsArrayFunc 类型
) -> NDArray[_SCT]: ...             # 返回类型为 NDArray[_SCT] 的函数重载

@overload
def ones(
    shape: _ShapeLike,              # 参数 shape 的类型为 _ShapeLike
    dtype: DTypeLike,               # dtype 参数的类型为 DTypeLike
    order: _OrderCF = ...,          # order 参数,默认为 _OrderCF 类型
    *,
    device: None | L["cpu"] = ...,  # device 参数,默认为 None 或 "cpu" 字面值类型
    like: _SupportsArray
    a: _ArrayLike[_SCT],  # 定义变量a,其类型为_ArrayLike[_SCT],表示可能是某种数组类型
    dtype: None = ...,    # 定义变量dtype,默认为None,可能表示数据类型
    order: _OrderKACF = ...,  # 定义变量order,默认为_OrdeKACF类型,可能表示数组的存储顺序
    subok: bool = ...,    # 定义变量subok,默认为bool类型,可能表示是否允许返回子类对象
    shape: None | _ShapeLike = ...,  # 定义变量shape,默认为None或者_ShapeLike类型,可能表示数组的形状
    *,                    # 分隔位置参数和关键字参数的分隔符
    device: None | L["cpu"] = ...,  # 定义变量device,默认为None或者L["cpu"]类型,可能表示数据所在的设备
# 定义一个函数签名,声明返回类型为 NDArray[_SCT]
def ones_like(
    a: object,
    dtype: None = ...,
    order: _OrderKACF = ...,
    subok: bool = ...,
    shape: None | _ShapeLike= ...,
    *,
    device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...

# 函数重载:根据输入参数 a 的类型和 dtype 创建形状相同的全 1 数组
@overload
def ones_like(
    a: Any,
    dtype: _DTypeLike[_SCT],
    order: _OrderKACF = ...,
    subok: bool = ...,
    shape: None | _ShapeLike= ...,
    *,
    device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...

# 函数重载:根据输入参数 a 的类型和 dtype 创建形状相同的全 1 数组
@overload
def ones_like(
    a: Any,
    dtype: DTypeLike,
    order: _OrderKACF = ...,
    subok: bool = ...,
    shape: None | _ShapeLike= ...,
    *,
    device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...

# 函数签名:根据形状、填充值和数据类型创建全填充数组
def full(
    shape: _ShapeLike,
    fill_value: Any,
    dtype: None = ...,
    order: _OrderCF = ...,
    *,
    device: None | L["cpu"] = ...,
    like: _SupportsArrayFunc = ...,
) -> NDArray[Any]: ...

# 函数重载:根据形状、填充值、数据类型和类似对象创建全填充数组
@overload
def full(
    shape: _ShapeLike,
    fill_value: Any,
    dtype: _DTypeLike[_SCT],
    order: _OrderCF = ...,
    *,
    device: None | L["cpu"] = ...,
    like: _SupportsArrayFunc = ...,
) -> NDArray[_SCT]: ...

# 函数重载:根据形状、填充值、数据类型创建全填充数组
@overload
def full(
    shape: _ShapeLike,
    fill_value: Any,
    dtype: DTypeLike,
    order: _OrderCF = ...,
    *,
    device: None | L["cpu"] = ...,
    like: _SupportsArrayFunc = ...,
) -> NDArray[Any]: ...

# 函数签名:根据输入数组 a 的形状创建全填充数组,填充值为指定值
@overload
def full_like(
    a: _ArrayType,
    fill_value: Any,
    dtype: None = ...,
    order: _OrderKACF = ...,
    subok: L[True] = ...,
    shape: None = ...,
    *,
    device: None | L["cpu"] = ...,
) -> _ArrayType: ...

# 函数重载:根据输入数组 a 的形状创建全填充数组,填充值为指定值,数据类型为指定类型
@overload
def full_like(
    a: _ArrayLike[_SCT],
    fill_value: Any,
    dtype: None = ...,
    order: _OrderKACF = ...,
    subok: bool = ...,
    shape: None | _ShapeLike = ...,
    *,
    device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...

# 函数重载:根据输入对象 a 的形状创建全填充数组,填充值为指定值
@overload
def full_like(
    a: object,
    fill_value: Any,
    dtype: None = ...,
    order: _OrderKACF = ...,
    subok: bool = ...,
    shape: None | _ShapeLike= ...,
    *,
    device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...

# 函数重载:根据输入对象 a 的形状创建全填充数组,填充值为指定值,数据类型为指定类型
@overload
def full_like(
    a: Any,
    fill_value: Any,
    dtype: _DTypeLike[_SCT],
    order: _OrderKACF = ...,
    subok: bool = ...,
    shape: None | _ShapeLike= ...,
    *,
    device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...

# 函数重载:根据输入对象 a 的形状创建全填充数组,填充值为指定值,数据类型为指定类型
@overload
def full_like(
    a: Any,
    fill_value: Any,
    dtype: DTypeLike,
    order: _OrderKACF = ...,
    subok: bool = ...,
    shape: None | _ShapeLike= ...,
    *,
    device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...

# 函数签名:计算数组中非零元素的数量
@overload
def count_nonzero(
    a: ArrayLike,
    axis: None = ...,
    *,
    keepdims: L[False] = ...,
) -> int: ...

# 函数签名:计算数组中非零元素的数量,可以指定计算的轴
@overload
def count_nonzero(
    a: ArrayLike,
    axis: _ShapeLike = ...,
    *,
    keepdims: bool = ...,
) -> Any: ...  # TODO: np.intp or ndarray[np.intp]

# 函数签名:判断数组是否按 Fortran 顺序存储
def isfortran(a: NDArray[Any] | generic) -> bool: ...

# 函数签名:返回数组中非零元素的索引数组
def argwhere(a: ArrayLike) -> NDArray[intp]: ...

# 函数签名:返回数组中所有非零元素的扁平索引数组
def flatnonzero(a: ArrayLike) -> NDArray[intp]: ...

# 函数签名:计算两个数组的相关性
@overload
def correlate(
    a: _ArrayLikeUnknown,
    v: _ArrayLikeUnknown,
    mode: _CorrelateMode = ...,


    # v: _ArrayLikeUnknown 是一个变量,其类型可能是数组或类似数组的结构,具体类型未知
    # mode: _CorrelateMode 是一个变量,其类型为 _CorrelateMode 类型,默认值为 ...
# 定义 correlate 函数的多个重载,计算两个数组的相关性
@overload
def correlate(
    a: _ArrayLikeBool_co,
    v: _ArrayLikeBool_co,
    mode: _CorrelateMode = ...,
) -> NDArray[np.bool]: ...
@overload
def correlate(
    a: _ArrayLikeUInt_co,
    v: _ArrayLikeUInt_co,
    mode: _CorrelateMode = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def correlate(
    a: _ArrayLikeInt_co,
    v: _ArrayLikeInt_co,
    mode: _CorrelateMode = ...,
) -> NDArray[signedinteger[Any]]: ...
@overload
def correlate(
    a: _ArrayLikeFloat_co,
    v: _ArrayLikeFloat_co,
    mode: _CorrelateMode = ...,
) -> NDArray[floating[Any]]: ...
@overload
def correlate(
    a: _ArrayLikeComplex_co,
    v: _ArrayLikeComplex_co,
    mode: _CorrelateMode = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def correlate(
    a: _ArrayLikeTD64_co,
    v: _ArrayLikeTD64_co,
    mode: _CorrelateMode = ...,
) -> NDArray[timedelta64]: ...
@overload
def correlate(
    a: _ArrayLikeObject_co,
    v: _ArrayLikeObject_co,
    mode: _CorrelateMode = ...,
) -> NDArray[object_]: ...

# 定义 convolve 函数的多个重载,计算两个数组的卷积
@overload
def convolve(
    a: _ArrayLikeUnknown,
    v: _ArrayLikeUnknown,
    mode: _CorrelateMode = ...,
) -> NDArray[Any]: ...
@overload
def convolve(
    a: _ArrayLikeBool_co,
    v: _ArrayLikeBool_co,
    mode: _CorrelateMode = ...,
) -> NDArray[np.bool]: ...
@overload
def convolve(
    a: _ArrayLikeUInt_co,
    v: _ArrayLikeUInt_co,
    mode: _CorrelateMode = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def convolve(
    a: _ArrayLikeInt_co,
    v: _ArrayLikeInt_co,
    mode: _CorrelateMode = ...,
) -> NDArray[signedinteger[Any]]: ...
@overload
def convolve(
    a: _ArrayLikeFloat_co,
    v: _ArrayLikeFloat_co,
    mode: _CorrelateMode = ...,
) -> NDArray[floating[Any]]: ...
@overload
def convolve(
    a: _ArrayLikeComplex_co,
    v: _ArrayLikeComplex_co,
    mode: _CorrelateMode = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def convolve(
    a: _ArrayLikeTD64_co,
    v: _ArrayLikeTD64_co,
    mode: _CorrelateMode = ...,
) -> NDArray[timedelta64]: ...
@overload
def convolve(
    a: _ArrayLikeObject_co,
    v: _ArrayLikeObject_co,
    mode: _CorrelateMode = ...,
) -> NDArray[object_]: ...

# 定义 outer 函数的多个重载,计算两个数组的外积
@overload
def outer(
    a: _ArrayLikeUnknown,
    b: _ArrayLikeUnknown,
    out: None = ...,
) -> NDArray[Any]: ...
@overload
def outer(
    a: _ArrayLikeBool_co,
    b: _ArrayLikeBool_co,
    out: None = ...,
) -> NDArray[np.bool]: ...
@overload
def outer(
    a: _ArrayLikeUInt_co,
    b: _ArrayLikeUInt_co,
    out: None = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def outer(
    a: _ArrayLikeInt_co,
    b: _ArrayLikeInt_co,
    out: None = ...,
) -> NDArray[signedinteger[Any]]: ...
@overload
def outer(
    a: _ArrayLikeFloat_co,
    b: _ArrayLikeFloat_co,
    out: None = ...,
) -> NDArray[floating[Any]]: ...
@overload
def outer(
    a: _ArrayLikeComplex_co,
    b: _ArrayLikeComplex_co,
    out: None = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def outer(
    a: _ArrayLikeTD64_co,
    b: _ArrayLikeTD64_co,
    out: None = ...,
) -> NDArray[timedelta64]: ...
@overload
def outer(
    a: _ArrayLikeObject_co,
    b: _ArrayLikeObject_co,
    out: None = ...,
) -> NDArray[object_]: ...
    b: _ArrayLikeTD64_co,
    out: None = ...,


# 声明变量b,其类型为_ArrayLikeTD64_co
b: _ArrayLikeTD64_co,
# 声明变量out,默认值为None
out: None = ...,
# 定义了一个函数签名,声明其返回类型为 NDArray[timedelta64]
) -> NDArray[timedelta64]: ...

# 函数重载:定义了一个函数 outer,接受两个 _ArrayLikeObject_co 类型的参数 a 和 b,并且 out 参数默认为 None
@overload
def outer(
    a: _ArrayLikeObject_co,
    b: _ArrayLikeObject_co,
    out: None = ...,
) -> NDArray[object_]: ...

# 函数重载:定义了一个函数 outer,接受三个可能类型的参数 a、b 和 out,其中 out 参数类型为 _ArrayType
@overload
def outer(
    a: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeObject_co,
    b: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeObject_co,
    out: _ArrayType,
) -> _ArrayType: ...

# 函数重载:定义了一个函数 tensordot,接受两个 _ArrayLikeUnknown 类型的参数 a 和 b,还有一个可选的 axes 参数,其默认类型为 int 或元组 _ShapeLike
@overload
def tensordot(
    a: _ArrayLikeUnknown,
    b: _ArrayLikeUnknown,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[Any]: ...

# 以下是 tensordot 函数的多个重载版本,分别适用于不同类型的数组 a 和 b,返回的数组类型分别是 bool、unsigned integer、signed integer、float、complex 和 timedelta64
@overload
def tensordot(
    a: _ArrayLikeBool_co,
    b: _ArrayLikeBool_co,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[np.bool]: ...

@overload
def tensordot(
    a: _ArrayLikeUInt_co,
    b: _ArrayLikeUInt_co,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[unsignedinteger[Any]]: ...

@overload
def tensordot(
    a: _ArrayLikeInt_co,
    b: _ArrayLikeInt_co,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[signedinteger[Any]]: ...

@overload
def tensordot(
    a: _ArrayLikeFloat_co,
    b: _ArrayLikeFloat_co,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[floating[Any]]: ...

@overload
def tensordot(
    a: _ArrayLikeComplex_co,
    b: _ArrayLikeComplex_co,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[complexfloating[Any, Any]]: ...

@overload
def tensordot(
    a: _ArrayLikeTD64_co,
    b: _ArrayLikeTD64_co,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[timedelta64]: ...

@overload
def tensordot(
    a: _ArrayLikeObject_co,
    b: _ArrayLikeObject_co,
    axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[object_]: ...

# 函数重载:定义了一个函数 roll,接受一个 _ArrayLike[_SCT] 类型的参数 a,一个 _ShapeLike 类型的参数 shift,以及一个可选的 axis 参数,其类型为 None 或 _ShapeLike
@overload
def roll(
    a: _ArrayLike[_SCT],
    shift: _ShapeLike,
    axis: None | _ShapeLike = ...,
) -> NDArray[_SCT]: ...

# 函数重载:定义了一个函数 roll,接受一个 ArrayLike 类型的参数 a,一个 _ShapeLike 类型的参数 shift,以及一个可选的 axis 参数,其类型为 None 或 _ShapeLike
@overload
def roll(
    a: ArrayLike,
    shift: _ShapeLike,
    axis: None | _ShapeLike = ...,
) -> NDArray[Any]: ...

# 定义了一个函数 rollaxis,接受一个 NDArray[_SCT] 类型的参数 a,一个整数类型的参数 axis,以及一个可选的 start 参数,默认为 ...
def rollaxis(
    a: NDArray[_SCT],
    axis: int,
    start: int = ...,
) -> NDArray[_SCT]: ...

# 定义了一个函数 moveaxis,接受一个 NDArray[_SCT] 类型的参数 a,两个 _ShapeLike 类型的参数 source 和 destination
def moveaxis(
    a: NDArray[_SCT],
    source: _ShapeLike,
    destination: _ShapeLike,
) -> NDArray[_SCT]: ...

# 函数重载:定义了一个函数 cross,接受两个 _ArrayLikeUnknown 类型的参数 x1 和 x2,还有四个可选的整数类型参数 axisa、axisb、axisc 和 axis
@overload
def cross(
    x1: _ArrayLikeUnknown,
    x2: _ArrayLikeUnknown,
    axisa: int = ...,
    axisb: int = ...,
    axisc: int = ...,
    axis: None | int = ...,
) -> NDArray[Any]: ...

# 函数重载:定义了一个函数 cross,接受两个 _ArrayLikeBool_co 类型的参数 x1 和 x2,还有四个可选的整数类型参数 axisa、axisb、axisc 和 axis,但是此函数不返回值
@overload
def cross(
    x1: _ArrayLikeBool_co,
    x2: _ArrayLikeBool_co,
    axisa: int = ...,
    axisb: int = ...,
    axisc: int = ...,
    axis: None | int = ...,
) -> NoReturn: ...

# 函数重载:定义了一个函数 cross,接受两个 _ArrayLikeUInt_co 类型的参数 x1 和 x2,还有四个可选的整数类型参数 axisa、axisb、axisc 和 axis,返回的数组类型为 unsigned integer
@overload
def cross(
    x1: _ArrayLikeUInt_co,
    x2: _ArrayLikeUInt_co,
    axisa: int = ...,
    axisb: int = ...,
    axisc: int = ...,
    axis: None | int = ...,
) -> NDArray[unsignedinteger[Any]]: ...

# 函数重载:定义了一个函数 cross,接受两个 _ArrayLikeInt_co 类型的参数 x1 和 x2,还有四个可选的整数类型参数 axisa、axisb、axisc 和 axis,返回的数组类型为 signed integer
@overload
def cross(
    x1: _ArrayLikeInt_co,
    x2: _ArrayLikeInt_co,
    axisa: int = ...,
    axisb: int = ...,
    axisc: int = ...,
    axis: None | int = ...,
) -> NDArray[signedinteger[Any]]: ...

# 此处省略了其余 cross 函数重载的注释,因为示例已经包含了详细的描述
    x2: _ArrayLikeFloat_co,
    # x2 是一个类型注解,表示 x2 是一个类似数组的浮点数类型的协变类型
    axisa: int = ...,
    # axisa 是一个整数类型的参数,默认值为省略号(...)
    axisb: int = ...,
    # axisb 是一个整数类型的参数,默认值为省略号(...)
    axisc: int = ...,
    # axisc 是一个整数类型的参数,默认值为省略号(...)
    axis: None | int = ...,
    # axis 是一个可以是 None 或整数类型的参数,默认值为省略号(...)
# 定义一个函数,计算两个数组的叉积
def cross(
    x1: _ArrayLikeComplex_co,
    x2: _ArrayLikeComplex_co,
    axisa: int = ...,
    axisb: int = ...,
    axisc: int = ...,
    axis: None | int = ...,
) -> NDArray[complexfloating[Any, Any]]: ...

# 定义一个函数,生成指定维度的索引数组
def indices(
    dimensions: Sequence[int],
    dtype: type[int] = ...,
    sparse: L[False] = ...,
) -> NDArray[int_]: ...

# 定义一个函数,根据给定函数和形状生成数组
def fromfunction(
    function: Callable[..., _T],
    shape: Sequence[int],
    *,
    dtype: DTypeLike = ...,
    like: _SupportsArrayFunc = ...,
    **kwargs: Any,
) -> _T: ...

# 定义一个函数,判断一个元素是否为标量类型
def isscalar(element: object) -> TypeGuard[
    generic | bool | int | float | complex | str | bytes | memoryview
]: ...

# 定义一个函数,将一个数字转换为指定进制的字符串表示
def binary_repr(num: SupportsIndex, width: None | int = ...) -> str: ...

# 定义一个函数,将一个数字转换为指定进制的字符串表示
def base_repr(
    number: SupportsAbs[float],
    base: float = ...,
    padding: SupportsIndex = ...,
) -> str: ...

# 定义一个函数,生成指定维度的单位矩阵
def identity(
    n: int,
    dtype: None = ...,
    *,
    like: _SupportsArrayFunc = ...,
) -> NDArray[float64]: ...

# 定义一个函数,判断两个数组是否在误差范围内相等
def allclose(
    a: ArrayLike,
    b: ArrayLike,
    rtol: ArrayLike = ...,
    atol: ArrayLike = ...,
    equal_nan: bool = ...,
) -> bool: ...

# 定义一个函数,判断两个数或数组是否在误差范围内相等
def isclose(
    a: _ScalarLike_co,
    b: _ScalarLike_co,
    rtol: ArrayLike = ...,
    atol: ArrayLike = ...,
    equal_nan: bool = ...,
) -> np.bool: ...

# 定义一个函数,判断两个数组是否完全相等
def array_equal(a1: ArrayLike, a2: ArrayLike, equal_nan: bool = ...) -> bool: ...

# 定义一个函数,判断两个数组是否等价
def array_equiv(a1: ArrayLike, a2: ArrayLike) -> bool: ...

# 定义一个函数,将数组转换为指定数据类型
def astype(
    x: NDArray[Any],
    dtype: _DTypeLike[_SCT],
    copy: bool = ...,
) -> NDArray[_SCT]: ...
# 定义一个函数,返回类型为 `NDArray[Any]`
) -> NDArray[Any]: ...

.\numpy\numpy\_core\numerictypes.py

"""
numerictypes: Define the numeric type objects

This module is designed so "from numerictypes import \\*" is safe.
Exported symbols include:

  Dictionary with all registered number types (including aliases):
    sctypeDict

  Type objects (not all will be available, depends on platform):
      see variable sctypes for which ones you have

    Bit-width names

    int8 int16 int32 int64 int128
    uint8 uint16 uint32 uint64 uint128
    float16 float32 float64 float96 float128 float256
    complex32 complex64 complex128 complex192 complex256 complex512
    datetime64 timedelta64

    c-based names

    bool

    object_

    void, str_

    byte, ubyte,
    short, ushort
    intc, uintc,
    intp, uintp,
    int_, uint,
    longlong, ulonglong,

    single, csingle,
    double, cdouble,
    longdouble, clongdouble,

   As part of the type-hierarchy:    xx -- is bit-width

   generic
     +-> bool                                   (kind=b)
     +-> number
     |   +-> integer
     |   |   +-> signedinteger     (intxx)      (kind=i)
     |   |   |     byte
     |   |   |     short
     |   |   |     intc
     |   |   |     intp
     |   |   |     int_
     |   |   |     longlong
     |   |   \\-> unsignedinteger  (uintxx)     (kind=u)
     |   |         ubyte
     |   |         ushort
     |   |         uintc
     |   |         uintp
     |   |         uint
     |   |         ulonglong
     |   +-> inexact
     |       +-> floating          (floatxx)    (kind=f)
     |       |     half
     |       |     single
     |       |     double
     |       |     longdouble
     |       \\-> complexfloating  (complexxx)  (kind=c)
     |             csingle
     |             cdouble
     |             clongdouble
     +-> flexible
     |   +-> character
     |   |     bytes_                           (kind=S)
     |   |     str_                             (kind=U)
     |   |
     |   \\-> void                              (kind=V)
     \\-> object_ (not used much)               (kind=O)

"""
import numbers  # 导入标准库中的 numbers 模块,用于数字类型相关的操作和判断
import warnings  # 导入警告模块,用于发出警告消息

from . import multiarray as ma  # 导入当前包中的 multiarray 模块,并使用别名 ma
from .multiarray import (  # 从 multiarray 模块中导入以下内容:
        ndarray, array, dtype, datetime_data, datetime_as_string,
        busday_offset, busday_count, is_busday, busdaycalendar
        )
from .._utils import set_module  # 从上级包中的 _utils 模块中导入 set_module 函数

# we add more at the bottom
__all__ = [  # 设置模块中可以被导入的公开对象列表
    'ScalarType', 'typecodes', 'issubdtype', 'datetime_data', 
    'datetime_as_string', 'busday_offset', 'busday_count', 
    'is_busday', 'busdaycalendar', 'isdtype'
]

# we don't need all these imports, but we need to keep them for compatibility
# for users using np._core.numerictypes.UPPER_TABLE
from ._string_helpers import (  # 从 _string_helpers 模块中导入以下内容:
    english_lower, english_upper, english_capitalize, LOWER_TABLE, UPPER_TABLE
)

from ._type_aliases import (  # 从 _type_aliases 模块中导入以下内容:
    sctypeDict, allTypes, sctypes
)
from ._dtype import _kind_name  # 从 _dtype 模块中导入 _kind_name 函数

# we don't export these for import *, but we do want them accessible
# as numerictypes.bool, etc.
from builtins import bool, int, float, complex, object, str, bytes  # 从内置模块 builtins 中导入标准类型对象
# 我们稍后会用到这个变量
generic = allTypes['generic']

# 定义所有标量类型的排序列表
# 这些类型按照精度从低到高排序
genericTypeRank = ['bool', 'int8', 'uint8', 'int16', 'uint16',
                   'int32', 'uint32', 'int64', 'uint64', 'int128',
                   'uint128', 'float16',
                   'float32', 'float64', 'float80', 'float96', 'float128',
                   'float256',
                   'complex32', 'complex64', 'complex128', 'complex160',
                   'complex192', 'complex256', 'complex512', 'object']

@set_module('numpy')
def maximum_sctype(t):
    """
    根据输入的类型,返回同种类中最高精度的标量类型。

    .. deprecated:: 2.0
        建议改用显式的 dtype,如 int64 或 float64。

    Parameters
    ----------
    t : dtype 或 dtype 指定符
        输入的数据类型。可以是一个 `dtype` 对象或可以转换为 `dtype` 的对象。

    Returns
    -------
    out : dtype
        与 `t` 同类 (`dtype.kind`) 中最高精度的数据类型。

    See Also
    --------
    obj2sctype, mintypecode, sctype2char
    dtype

    Examples
    --------
    >>> from numpy._core.numerictypes import maximum_sctype
    >>> maximum_sctype(int)
    <class 'numpy.int64'>
    >>> maximum_sctype(np.uint8)
    <class 'numpy.uint64'>
    >>> maximum_sctype(complex)
    <class 'numpy.complex256'> # 结果可能会有所不同

    >>> maximum_sctype(str)
    <class 'numpy.str_'>

    >>> maximum_sctype('i2')
    <class 'numpy.int64'>
    >>> maximum_sctype('f4')
    <class 'numpy.float128'> # 结果可能会有所不同

    """

    # 在 NumPy 2.0 中已弃用,2023-07-11
    warnings.warn(
        "`maximum_sctype` 已弃用。建议改用显式的 dtype,如 int64 或 float64。"
        " (在 NumPy 2.0 中弃用)",
        DeprecationWarning,
        stacklevel=2
    )

    # 获取对象的标量类型
    g = obj2sctype(t)
    if g is None:
        return t
    t = g
    # 获取基本类型的名称
    base = _kind_name(dtype(t))
    # 如果基本类型存在于 sctypes 中,则返回最高精度的数据类型
    if base in sctypes:
        return sctypes[base][-1]
    else:
        return t


@set_module('numpy')
def issctype(rep):
    """
    判断给定对象是否表示标量数据类型。

    Parameters
    ----------
    rep : 任意类型
        如果 `rep` 是标量数据类型的实例,则返回 True。否则返回 False。

    Returns
    -------
    out : bool
        检查 `rep` 是否为标量数据类型的布尔结果。

    See Also
    --------
    issubsctype, issubdtype, obj2sctype, sctype2char

    Examples
    --------
    >>> from numpy._core.numerictypes import issctype
    >>> issctype(np.int32)
    True
    >>> issctype(list)
    False
    >>> issctype(1.1)
    False

    字符串也是标量类型:

    >>> issctype(np.dtype('str'))
    True

    """
    # 如果 rep 不是类型或 dtype 的实例,则返回 False
    if not isinstance(rep, (type, dtype)):
        return False
    try:
        # 尝试获取 rep 的标量类型
        res = obj2sctype(rep)
        # 如果 res 存在且不等于 object_,则返回 True
        if res and res != object_:
            return True
        return False
    except Exception:
        return False


@set_module('numpy')
def obj2sctype(rep, default=None):
    """
    将输入转换为其对应的标量数据类型。
    # 返回对象的标量数据类型或者其在 NumPy 中的等效类型

    Parameters
    ----------
    rep : any
        要获取其类型的对象。
    default : any, optional
        如果提供,则用于无法确定类型的对象。如果未提供,则对于这些对象返回 None。

    Returns
    -------
    dtype : dtype or Python type
        `rep` 的数据类型。

    See Also
    --------
    sctype2char, issctype, issubsctype, issubdtype

    Examples
    --------
    >>> from numpy._core.numerictypes import obj2sctype
    >>> obj2sctype(np.int32)
    <class 'numpy.int32'>
    >>> obj2sctype(np.array([1., 2.]))
    <class 'numpy.float64'>
    >>> obj2sctype(np.array([1.j]))
    <class 'numpy.complex128'>

    >>> obj2sctype(dict)
    <class 'numpy.object_'>
    >>> obj2sctype('string')

    >>> obj2sctype(1, default=list)
    <class 'list'>
    
    """
    # 防止抽象类被向上转型
    if isinstance(rep, type) and issubclass(rep, generic):
        return rep
    # 从数组中提取 dtype
    if isinstance(rep, ndarray):
        return rep.dtype.type
    # 如果转换为 dtype 失败则返回默认值
    try:
        res = dtype(rep)
    except Exception:
        return default
    else:
        return res.type
# 设置模块为 'numpy'
@set_module('numpy')
# 定义函数,判断一个类是否是另一个类的子类
def issubclass_(arg1, arg2):
    """
    Determine if a class is a subclass of a second class.

    `issubclass_` is equivalent to the Python built-in ``issubclass``,
    except that it returns False instead of raising a TypeError if one
    of the arguments is not a class.

    Parameters
    ----------
    arg1 : class
        Input class. True is returned if `arg1` is a subclass of `arg2`.
    arg2 : class or tuple of classes.
        Input class. If a tuple of classes, True is returned if `arg1` is a
        subclass of any of the tuple elements.

    Returns
    -------
    out : bool
        Whether `arg1` is a subclass of `arg2` or not.

    See Also
    --------
    issubsctype, issubdtype, issctype

    Examples
    --------
    >>> np.issubclass_(np.int32, int)
    False
    >>> np.issubclass_(np.int32, float)
    False
    >>> np.issubclass_(np.float64, float)
    True

    """
    try:
        # 调用内置函数 issubclass 检查 arg1 是否是 arg2 的子类
        return issubclass(arg1, arg2)
    except TypeError:
        # 若 TypeError 异常发生,返回 False,不抛出异常
        return False


# 设置模块为 'numpy'
@set_module('numpy')
# 定义函数,判断第一个参数是否是第二个参数的子类
def issubsctype(arg1, arg2):
    """
    Determine if the first argument is a subclass of the second argument.

    Parameters
    ----------
    arg1, arg2 : dtype or dtype specifier
        Data-types.

    Returns
    -------
    out : bool
        The result.

    See Also
    --------
    issctype, issubdtype, obj2sctype

    Examples
    --------
    >>> from numpy._core import issubsctype
    >>> issubsctype('S8', str)
    False
    >>> issubsctype(np.array([1]), int)
    True
    >>> issubsctype(np.array([1]), float)
    False

    """
    # 使用 obj2sctype 函数获取 arg1 和 arg2 的数据类型,然后比较它们是否为子类关系
    return issubclass(obj2sctype(arg1), obj2sctype(arg2))


# 定义异常类 _PreprocessDTypeError
class _PreprocessDTypeError(Exception):
    pass


# 定义函数 _preprocess_dtype,预处理 dtype 参数
def _preprocess_dtype(dtype):
    """
    Preprocess dtype argument by:
      1. fetching type from a data type
      2. verifying that types are built-in NumPy dtypes
    """
    # 如果 dtype 是 masked array 的数据类型,提取其类型
    if isinstance(dtype, ma.dtype):
        dtype = dtype.type
    # 如果 dtype 是 ndarray 或者不在 allTypes.values() 中,抛出 _PreprocessDTypeError 异常
    if isinstance(dtype, ndarray) or dtype not in allTypes.values():
        raise _PreprocessDTypeError()
    # 返回处理后的 dtype
    return dtype


# 设置模块为 'numpy'
@set_module('numpy')
# 定义函数 isdtype,判断提供的 dtype 是否是指定数据类型种类的
def isdtype(dtype, kind):
    """
    Determine if a provided dtype is of a specified data type ``kind``.

    This function only supports built-in NumPy's data types.
    Third-party dtypes are not yet supported.

    Parameters
    ----------
    dtype : dtype
        The input dtype.
    kind : dtype or str or tuple of dtypes/strs.
        dtype or dtype kind. Allowed dtype kinds are:
        * ``'bool'`` : boolean kind
        * ``'signed integer'`` : signed integer data types
        * ``'unsigned integer'`` : unsigned integer data types
        * ``'integral'`` : integer data types
        * ``'real floating'`` : real-valued floating-point data types
        * ``'complex floating'`` : complex floating-point data types
        * ``'numeric'`` : numeric data types

    Returns
    -------
    out : bool

    See Also
    --------
    issubdtype

    Examples
    --------
    >>> import numpy as np

    """
    # 返回 obj2sctype 函数处理后的 dtype 是否符合指定的数据类型种类 kind
    return issubclass(obj2sctype(dtype), obj2sctype(kind))
    # 检查是否 np.float32 是 np.float64 的子类型,返回 False
    >>> np.isdtype(np.float32, np.float64)
    False
    # 检查是否 np.float32 是 "real floating" 中的类型,返回 True
    >>> np.isdtype(np.float32, "real floating")
    True
    # 检查 np.complex128 是否是 "real floating" 或 "complex floating" 中的类型,返回 True
    >>> np.isdtype(np.complex128, ("real floating", "complex floating"))
    True
    
    """
    尝试对 dtype 进行预处理,确保其为 NumPy 的 dtype 类型
    """
    try:
        dtype = _preprocess_dtype(dtype)
    except _PreprocessDTypeError:
        # 如果出现 _PreprocessDTypeError,则抛出 TypeError,指示 dtype 参数必须是 NumPy 的 dtype 类型
        raise TypeError(
            "dtype argument must be a NumPy dtype, "
            f"but it is a {type(dtype)}."
        ) from None
    
    # 如果 kind 是一个 tuple,则将其赋值给 input_kinds,否则将 kind 转为 tuple 并赋值给 input_kinds
    input_kinds = kind if isinstance(kind, tuple) else (kind,)
    
    # 创建一个空集合 processed_kinds,用于存储处理后的数据类型
    processed_kinds = set()
    
    # 遍历 input_kinds 中的每一个 kind
    for kind in input_kinds:
        # 如果 kind 是 "bool",则将 allTypes["bool"] 添加到 processed_kinds 中
        if kind == "bool":
            processed_kinds.add(allTypes["bool"])
        # 如果 kind 是 "signed integer",则将 sctypes["int"] 中的所有元素添加到 processed_kinds 中
        elif kind == "signed integer":
            processed_kinds.update(sctypes["int"])
        # 如果 kind 是 "unsigned integer",则将 sctypes["uint"] 中的所有元素添加到 processed_kinds 中
        elif kind == "unsigned integer":
            processed_kinds.update(sctypes["uint"])
        # 如果 kind 是 "integral",则将 sctypes["int"] 和 sctypes["uint"] 中的所有元素添加到 processed_kinds 中
        elif kind == "integral":
            processed_kinds.update(sctypes["int"] + sctypes["uint"])
        # 如果 kind 是 "real floating",则将 sctypes["float"] 中的所有元素添加到 processed_kinds 中
        elif kind == "real floating":
            processed_kinds.update(sctypes["float"])
        # 如果 kind 是 "complex floating",则将 sctypes["complex"] 中的所有元素添加到 processed_kinds 中
        elif kind == "complex floating":
            processed_kinds.update(sctypes["complex"])
        # 如果 kind 是 "numeric",则将 sctypes["int"]、sctypes["uint"]、sctypes["float"] 和 sctypes["complex"] 中的所有元素添加到 processed_kinds 中
        elif kind == "numeric":
            processed_kinds.update(
                sctypes["int"] + sctypes["uint"] +
                sctypes["float"] + sctypes["complex"]
            )
        # 如果 kind 是字符串但不是已知的类型名,则抛出 ValueError
        elif isinstance(kind, str):
            raise ValueError(
                "kind argument is a string, but"
                f" {repr(kind)} is not a known kind name."
            )
        else:
            # 否则,尝试对 kind 进行预处理,将其添加到 processed_kinds 中
            try:
                kind = _preprocess_dtype(kind)
            except _PreprocessDTypeError:
                # 如果预处理失败,则抛出 TypeError,指示 kind 参数必须是 NumPy 的 dtype 类型或字符串
                raise TypeError(
                    "kind argument must be comprised of "
                    "NumPy dtypes or strings only, "
                    f"but is a {type(kind)}."
                ) from None
            processed_kinds.add(kind)
    
    # 返回判断 dtype 是否在 processed_kinds 中的结果
    return dtype in processed_kinds
# 使用装饰器设置模块名称为'numpy'
@set_module('numpy')
# 定义函数issubdtype,用于检查第一个参数是否在类型层次结构中低于或等于第二个参数
def issubdtype(arg1, arg2):
    # 如果arg1不是generic的子类,则将其转换为dtype对象的类型
    if not issubclass_(arg1, generic):
        arg1 = dtype(arg1).type
    # 如果arg2不是generic的子类,则将其转换为dtype对象的类型
    if not issubclass_(arg2, generic):
        arg2 = dtype(arg2).type
    # 返回arg1是否为arg2的子类
    return issubclass(arg1, arg2)


# 使用装饰器设置模块名称为'numpy'
@set_module('numpy')
# 定义函数sctype2char,返回标量dtype的字符串表示形式
def sctype2char(sctype):
    # 将sctype转换为其对应的标量类型
    sctype = obj2sctype(sctype)
    # 如果无法识别sctype的类型,则引发ValueError异常
    if sctype is None:
        raise ValueError("unrecognized type")
    # 如果sctype不在sctypeDict的值中,则引发KeyError异常(兼容性)
    if sctype not in sctypeDict.values():
        raise KeyError(sctype)
    # 返回sctype对应的dtype对象的字符表示
    return dtype(sctype).char


# 定义函数_scalar_type_key,作为sorted函数的key函数
def _scalar_type_key(typ):
    # 获取typ对应的dtype对象
    dt = dtype(typ)
    # 返回一个元组,包含dtype的种类的小写形式和项目大小
    return (dt.kind.lower(), dt.itemsize)
# 定义标量类型列表,包括 int、float、complex、bool、bytes、str、memoryview
ScalarType = [int, float, complex, bool, bytes, str, memoryview]
# 将从 sctypeDict 中提取的类型值去重并排序,然后添加到 ScalarType 列表末尾
ScalarType += sorted(set(sctypeDict.values()), key=_scalar_type_key)
# 将 ScalarType 列表转换为元组,使其成为不可变对象
ScalarType = tuple(ScalarType)

# 现在将确定的类型添加到当前模块的全局命名空间中
for key in allTypes:
    globals()[key] = allTypes[key]
    # 将 key 添加到模块的 __all__ 列表中,以便该类型在 import * 时被导入
    __all__.append(key)

# 删除循环中的临时变量 key,以免污染命名空间
del key

# 定义类型码字典,将不同类型映射为对应的字符码
typecodes = {
    'Character': 'c',
    'Integer': 'bhilqnp',
    'UnsignedInteger': 'BHILQNP',
    'Float': 'efdg',
    'Complex': 'FDG',
    'AllInteger': 'bBhHiIlLqQnNpP',
    'AllFloat': 'efdgFDG',
    'Datetime': 'Mm',
    'All': '?bhilqnpBHILQNPefdgFDGSUVOMm'
}

# 向后兼容性 --- 废弃的名称
# 正式废弃:Numpy 1.20.0, 2020-10-19 (参见 numpy/__init__.py)
# 将 sctypeDict 赋值给 typeDict,用于向后兼容
typeDict = sctypeDict

# 定义函数 _register_types(),用于注册数值类型到 numbers 模块的类型系统中
def _register_types():
    # 将 integer 注册为 numbers.Integral 的子类
    numbers.Integral.register(integer)
    # 将 inexact 注册为 numbers.Complex 的子类
    numbers.Complex.register(inexact)
    # 将 floating 注册为 numbers.Real 的子类
    numbers.Real.register(floating)
    # 将 number 注册为 numbers.Number 的子类

# 执行 _register_types() 函数,注册数值类型到 numbers 模块的类型系统中
_register_types()

.\numpy\numpy\_core\numerictypes.pyi

```python`
# 导入必要的类型和函数

from typing import (
    Literal as L,  # 导入类型别名 L 作为 Literal
    Any,  # 导入 Any 类型
    TypeVar,  # 导入泛型类型变量 TypeVar
    TypedDict,  # 导入 TypedDict 类型
)

import numpy as np  # 导入 NumPy 库并使用 np 别名
from numpy import (  # 导入 NumPy 中的多个数据类型
    dtype,  # 导入 dtype 函数
    generic,  # 导入 generic 类型
    ubyte, ushort, uintc, ulong, ulonglong,  # 导入无符号整型别名
    byte, short, intc, long, longlong,  # 导入有符号整型别名
    half, single, double, longdouble,  # 导入浮点型别名
    csingle, cdouble, clongdouble,  # 导入复数浮点型别名
    datetime64, timedelta64,  # 导入日期时间和时间间隔类型
    object_, str_, bytes_, void,  # 导入对象、字符串、字节和空类型
)

from numpy._core._type_aliases import (  # 导入 NumPy 内部的类型别名
    sctypeDict as sctypeDict,  # 导入 sctypeDict 别名
)

from numpy._typing import DTypeLike  # 导入 NumPy 的类型别名 DTypeLike

_T = TypeVar("_T")  # 定义泛型类型变量 _T
_SCT = TypeVar("_SCT", bound=generic)  # 定义受限泛型类型变量 _SCT

class _TypeCodes(TypedDict):  # 定义 TypedDict 类型 _TypeCodes
    Character: L['c']  # 字符类型别名
    Integer: L['bhilqp']  # 整数类型别名
    UnsignedInteger: L['BHILQP']  # 无符号整数类型别名
    Float: L['efdg']  # 浮点数类型别名
    Complex: L['FDG']  # 复数类型别名
    AllInteger: L['bBhHiIlLqQpP']  # 所有整数类型别名
    AllFloat: L['efdgFDG']  # 所有浮点数类型别名
    Datetime: L['Mm']  # 日期时间类型别名
    All: L['?bhilqpBHILQPefdgFDGSUVOMm']  # 所有类型别名

__all__: list[str]  # 导出的所有符号列表,类型为 str

def isdtype(  # 定义函数 isdtype
    dtype: dtype[Any] | type[Any],  # 参数 dtype,可以是 dtype 或 type 类型
    kind: DTypeLike | tuple[DTypeLike, ...]  # 参数 kind,可以是 DTypeLike 或其元组
) -> bool:  # 返回布尔值

def issubdtype(arg1: DTypeLike, arg2: DTypeLike) -> bool:  # 定义函数 issubdtype,参数和返回类型都是布尔值

typecodes: _TypeCodes  # 定义类型别名 typecodes,类型为 _TypeCodes

ScalarType: tuple[  # 定义标量类型元组 ScalarType,包含多种数据类型
    type[int], type[float], type[complex],  # 整数、浮点数和复数类型
    type[bool], type[bytes], type[str],  # 布尔、字节和字符串类型
    type[memoryview], type[np.bool],  # 内存视图和 NumPy 布尔类型
    type[csingle], type[cdouble], type[clongdouble],  # 复数浮点数类型
    type[half], type[single], type[double], type[longdouble],  # 浮点数类型
    type[byte], type[short], type[intc], type[long],  # 整数类型
    type[longlong], type[timedelta64], type[datetime64],  # 时间间隔和日期时间类型
    type[object_], type[bytes_], type[str_],  # 对象、字节和字符串类型
    type[ubyte], type[ushort], type[uintc], type[ulong], type[ulonglong], type[void],  # 无符号整数类型和空类型
]

.\numpy\numpy\_core\overrides.py

# 导入必要的模块:collections, functools, os
# 导入自定义模块中的 set_module 和 getargspec 函数
"""Implementation of __array_function__ overrides from NEP-18."""
# 导入 numpy 的核心模块中的 _ArrayFunctionDispatcher 类
from numpy._core._multiarray_umath import (
    add_docstring, _get_implementing_args, _ArrayFunctionDispatcher
)

# 定义一个空集合 ARRAY_FUNCTIONS
ARRAY_FUNCTIONS = set()

# 描述了 like 参数的文档字符串模板
array_function_like_doc = (
    """like : array_like, optional
        Reference object to allow the creation of arrays which are not
        NumPy arrays. If an array-like passed in as ``like`` supports
        the ``__array_function__`` protocol, the result will be defined
        by it. In this case, it ensures the creation of an array object
        compatible with that passed in via this argument."""
)

# 替换公共 API 文档中的 ${ARRAY_FUNCTION_LIKE} 字符串为 array_function_like_doc
def set_array_function_like_doc(public_api):
    if public_api.__doc__ is not None:
        public_api.__doc__ = public_api.__doc__.replace(
            "${ARRAY_FUNCTION_LIKE}",
            array_function_like_doc,
        )
    return public_api

# 为 _ArrayFunctionDispatcher 类添加文档字符串
add_docstring(
    _ArrayFunctionDispatcher,
    """
    Class to wrap functions with checks for __array_function__ overrides.

    All arguments are required, and can only be passed by position.

    Parameters
    ----------
    dispatcher : function or None
        The dispatcher function that returns a single sequence-like object
        of all arguments relevant.  It must have the same signature (except
        the default values) as the actual implementation.
        If ``None``, this is a ``like=`` dispatcher and the
        ``_ArrayFunctionDispatcher`` must be called with ``like`` as the
        first (additional and positional) argument.
    implementation : function
        Function that implements the operation on NumPy arrays without
        overrides.  Arguments passed calling the ``_ArrayFunctionDispatcher``
        will be forwarded to this (and the ``dispatcher``) as if using
        ``*args, **kwargs``.

    Attributes
    ----------
    _implementation : function
        The original implementation passed in.
    """
)

# 为 _get_implementing_args 函数添加文档字符串
add_docstring(
    _get_implementing_args,
    """
    Collect arguments on which to call __array_function__.

    Parameters
    ----------
    relevant_args : iterable of array-like
        Iterable of possibly array-like arguments to check for
        __array_function__ methods.

    Returns
    -------
    Sequence of arguments with __array_function__ methods, in the order in
    which they should be called.
    """
)

# 定义一个命名元组 ArgSpec,用于描述函数的参数信息
ArgSpec = collections.namedtuple('ArgSpec', 'args varargs keywords defaults')

# 定义一个函数 verify_matching_signatures 用于验证调度函数的签名是否匹配
def verify_matching_signatures(implementation, dispatcher):
    """Verify that a dispatcher function has the right signature."""
    # 获取实现函数和调度函数的参数规范
    implementation_spec = ArgSpec(*getargspec(implementation))
    dispatcher_spec = ArgSpec(*getargspec(dispatcher))
    # 检查实现和调度器函数的参数规范是否一致
    if (implementation_spec.args != dispatcher_spec.args or
            implementation_spec.varargs != dispatcher_spec.varargs or
            implementation_spec.keywords != dispatcher_spec.keywords or
            (bool(implementation_spec.defaults) !=
             bool(dispatcher_spec.defaults)) or
            (implementation_spec.defaults is not None and
             len(implementation_spec.defaults) !=
             len(dispatcher_spec.defaults))):
        # 如果存在参数规范不一致,则抛出运行时错误,指明实现和调度器函数的函数签名不同
        raise RuntimeError('implementation and dispatcher for %s have '
                           'different function signatures' % implementation)
    
    # 检查实现函数是否有默认参数
    if implementation_spec.defaults is not None:
        # 如果实现函数有默认参数,则进一步检查调度器函数的默认参数是否全为 None
        if dispatcher_spec.defaults != (None,) * len(dispatcher_spec.defaults):
            # 如果调度器函数的默认参数不全为 None,则抛出运行时错误,指明调度器函数只能使用 None 作为默认参数值
            raise RuntimeError('dispatcher functions can only use None for '
                               'default argument values')
# 定义一个装饰器函数,用于实现 __array_function__ 协议的分发
def array_function_dispatch(dispatcher=None, module=None, verify=True,
                            docs_from_dispatcher=False):
    """Decorator for adding dispatch with the __array_function__ protocol.

    See NEP-18 for example usage.

    Parameters
    ----------
    dispatcher : callable or None
        Function that when called like ``dispatcher(*args, **kwargs)`` with
        arguments from the NumPy function call returns an iterable of
        array-like arguments to check for ``__array_function__``.

        If `None`, the first argument is used as the single `like=` argument
        and not passed on.  A function implementing `like=` must call its
        dispatcher with `like` as the first non-keyword argument.
    module : str, optional
        __module__ attribute to set on new function, e.g., ``module='numpy'``.
        By default, module is copied from the decorated function.
    verify : bool, optional
        If True, verify the that the signature of the dispatcher and decorated
        function signatures match exactly: all required and optional arguments
        should appear in order with the same names, but the default values for
        all optional arguments should be ``None``. Only disable verification
        if the dispatcher's signature needs to deviate for some particular
        reason, e.g., because the function has a signature like
        ``func(*args, **kwargs)``.
    docs_from_dispatcher : bool, optional
        If True, copy docs from the dispatcher function onto the dispatched
        function, rather than from the implementation. This is useful for
        functions defined in C, which otherwise don't have docstrings.

    Returns
    -------
    Function suitable for decorating the implementation of a NumPy function.

    """
    # 内部装饰器函数,用于实际装饰待分发函数的实现
    def decorator(implementation):
        # 如果 verify 为 True,则验证分发器和被装饰函数的签名是否匹配
        if verify:
            if dispatcher is not None:
                verify_matching_signatures(implementation, dispatcher)
            else:
                # 直接使用 __code__ 来验证签名类似于 verify_matching_signature
                co = implementation.__code__
                last_arg = co.co_argcount + co.co_kwonlyargcount - 1
                last_arg = co.co_varnames[last_arg]
                # 检查最后一个参数是否为 "like",且是否为关键字参数
                if last_arg != "like" or co.co_kwonlyargcount == 0:
                    raise RuntimeError(
                        "__array_function__ expects `like=` to be the last "
                        "argument and a keyword-only argument. "
                        f"{implementation} does not seem to comply.")

        # 如果 docs_from_dispatcher 为 True,则从分发器函数复制文档字符串到被分发函数
        if docs_from_dispatcher:
            add_docstring(implementation, dispatcher.__doc__)

        # 创建 _ArrayFunctionDispatcher 对象,将分发器和实现函数封装起来
        public_api = _ArrayFunctionDispatcher(dispatcher, implementation)
        # 使用 functools.wraps 将装饰器函数的属性复制到 public_api 上
        public_api = functools.wraps(implementation)(public_api)

        # 如果指定了 module,则设置 public_api 的 __module__ 属性
        if module is not None:
            public_api.__module__ = module

        # 将 public_api 添加到全局集合 ARRAY_FUNCTIONS 中
        ARRAY_FUNCTIONS.add(public_api)

        # 返回装饰后的 public_api 函数
        return public_api

    # 返回内部的装饰器函数
    return decorator
# 定义一个函数,用于生成特定的装饰器,其参数和 array_function_dispatcher 函数的顺序相反
def array_function_from_dispatcher(
        implementation, module=None, verify=True, docs_from_dispatcher=True):
    """Like array_function_dispatcher, but with function arguments flipped."""

    # 定义一个装饰器函数,接受一个调度函数作为参数
    def decorator(dispatcher):
        # 返回调用 array_function_dispatch 函数的结果,使用装饰器的参数和给定的实现函数
        return array_function_dispatch(
            dispatcher, module, verify=verify,
            docs_from_dispatcher=docs_from_dispatcher)(implementation)
    
    # 返回装饰器函数
    return decorator

.\numpy\numpy\_core\records.py

"""
This module contains a set of functions for record arrays.
"""
# 导入必要的模块和包
import os
import warnings
from collections import Counter
from contextlib import nullcontext

# 从模块_utils中导入set_module函数
from .._utils import set_module
# 从当前目录的子模块中导入numeric作为别名sb,导入numerictypes作为别名nt
from . import numeric as sb
from . import numerictypes as nt
# 从当前目录的子模块中导入arrayprint模块中的_get_legacy_print_mode函数
from .arrayprint import _get_legacy_print_mode

# 定义可导出的函数和类名列表
__all__ = [
    'record', 'recarray', 'format_parser', 'fromarrays', 'fromrecords',
    'fromstring', 'fromfile', 'array', 'find_duplicate',
]

# 将sb.ndarray赋值给ndarray,简化代码中的引用
ndarray = sb.ndarray

# 字节顺序转换字典,用于将字符表示的字节顺序映射为标准符号
_byteorderconv = {'b': '>',
                  'l': '<',
                  'n': '=',
                  'B': '>',
                  'L': '<',
                  'N': '=',
                  'S': 's',
                  's': 's',
                  '>': '>',
                  '<': '<',
                  '=': '=',
                  '|': '|',
                  'I': '|',
                  'i': '|'}

# 数字格式的正则表达式字典,使用numerictypes模块中的sctypeDict函数获取
# 允许多维度规范与元组语法的结合,例如 '(2,3)f4' 和 ' (  2 ,  3  )  f4  ' 都是合法的
numfmt = nt.sctypeDict


# 使用装饰器set_module将函数find_duplicate置于numpy.rec模块下
@set_module('numpy.rec')
def find_duplicate(list):
    """Find duplication in a list, return a list of duplicated elements"""
    return [
        item
        for item, counts in Counter(list).items()
        if counts > 1
    ]


# format_parser类的定义,用于将格式、名称和标题描述转换为dtype
@set_module('numpy.rec')
class format_parser:
    """
    Class to convert formats, names, titles description to a dtype.

    After constructing the format_parser object, the dtype attribute is
    the converted data-type:
    ``dtype = format_parser(formats, names, titles).dtype``

    Attributes
    ----------
    dtype : dtype
        The converted data-type.

    Parameters
    ----------
    formats : str or list of str
        The format description, either specified as a string with
        comma-separated format descriptions in the form ``'f8, i4, S5'``, or
        a list of format description strings  in the form
        ``['f8', 'i4', 'S5']``.
    names : str or list/tuple of str
        The field names, either specified as a comma-separated string in the
        form ``'col1, col2, col3'``, or as a list or tuple of strings in the
        form ``['col1', 'col2', 'col3']``.
        An empty list can be used, in that case default field names
        ('f0', 'f1', ...) are used.
    titles : sequence
        Sequence of title strings. An empty list can be used to leave titles
        out.
    aligned : bool, optional
        If True, align the fields by padding as the C-compiler would.
        Default is False.
    byteorder : str, optional
        If specified, all the fields will be changed to the
        provided byte-order.  Otherwise, the default byte-order is
        used. For all available string specifiers, see `dtype.newbyteorder`.

    See Also
    --------
    numpy.dtype, numpy.typename

    Examples
    --------
    >>> np.rec.format_parser(['<f8', '<i4'], ['col1', 'col2'],
    """
    """
    `names` and/or `titles` can be empty lists. If `titles` is an empty list,
    titles will simply not appear. If `names` is empty, default field names
    will be used.

    >>> np.rec.format_parser(['f8', 'i4', 'a5'], ['col1', 'col2', 'col3'],
    ...                      []).dtype
    dtype([('col1', '<f8'), ('col2', '<i4'), ('col3', '<S5')])
    >>> np.rec.format_parser(['<f8', '<i4', '<a5'], [], []).dtype
    dtype([('f0', '<f8'), ('f1', '<i4'), ('f2', 'S5')])

    """

    def __init__(self, formats, names, titles, aligned=False, byteorder=None):
        """ Initialize the record parser object with formats, field names, titles, alignment, and byte order """

        self._parseFormats(formats, aligned)
        self._setfieldnames(names, titles)
        self._createdtype(byteorder)

    def _parseFormats(self, formats, aligned=False):
        """ Parse the field formats based on input formats and alignment """

        if formats is None:
            raise ValueError("Need formats argument")
        if isinstance(formats, list):
            # Create structured dtype from list of formats
            dtype = sb.dtype(
                [
                    ('f{}'.format(i), format_) 
                    for i, format_ in enumerate(formats)
                ],
                aligned,
            )
        else:
            # Create structured dtype from single format string
            dtype = sb.dtype(formats, aligned)
        
        fields = dtype.fields
        if fields is None:
            # If fields are not parsed correctly, create a default dtype
            dtype = sb.dtype([('f1', dtype)], aligned)
            fields = dtype.fields
        
        keys = dtype.names
        # Store the formats of each field
        self._f_formats = [fields[key][0] for key in keys]
        # Store the offsets of each field
        self._offsets = [fields[key][1] for key in keys]
        # Store the number of fields
        self._nfields = len(keys)

    def _setfieldnames(self, names, titles):
        """ Convert input field names into a list and assign to the _names attribute """

        if names:
            if type(names) in [list, tuple]:
                pass
            elif isinstance(names, str):
                # Split comma-separated string into list of names
                names = names.split(',')
            else:
                raise NameError("illegal input names %s" % repr(names))

            self._names = [n.strip() for n in names[:self._nfields]]
        else:
            self._names = []

        # Assign default names if not enough names are specified
        self._names += ['f%d' % i for i in range(len(self._names),
                                                 self._nfields)]
        
        # Check for duplicate names
        _dup = find_duplicate(self._names)
        if _dup:
            raise ValueError("Duplicate field names: %s" % _dup)

        if titles:
            self._titles = [n.strip() for n in titles[:self._nfields]]
        else:
            self._titles = []
            titles = []

        # Fill titles with None for fields without specific titles
        if self._nfields > len(titles):
            self._titles += [None] * (self._nfields - len(titles))
    # 定义一个私有方法 _createdtype,用于创建一个新的数据类型 dtype
    def _createdtype(self, byteorder):
        # 根据给定的属性创建一个结构化数据类型 dtype
        dtype = sb.dtype({
            'names': self._names,       # 使用 self._names 定义字段名
            'formats': self._f_formats, # 使用 self._f_formats 定义字段格式
            'offsets': self._offsets,   # 使用 self._offsets 定义字段偏移量
            'titles': self._titles,     # 使用 self._titles 定义字段标题
        })
        # 如果传入了 byteorder 参数,则将其转换为对应的字节顺序,并更新 dtype
        if byteorder is not None:
            byteorder = _byteorderconv[byteorder[0]]  # 获取对应的字节顺序
            dtype = dtype.newbyteorder(byteorder)     # 调整 dtype 的字节顺序为新的顺序

        # 将创建的数据类型 dtype 赋值给当前对象的 self.dtype 属性
        self.dtype = dtype
class record(nt.void):
    """A data-type scalar that allows field access as attribute lookup.
    """

    # manually set name and module so that this class's type shows up
    # as numpy.record when printed
    __name__ = 'record'
    __module__ = 'numpy'

    def __repr__(self):
        # 如果打印模式小于或等于 113,返回对象的字符串表示形式
        if _get_legacy_print_mode() <= 113:
            return self.__str__()
        # 否则调用父类的 __repr__ 方法
        return super().__repr__()

    def __str__(self):
        # 如果打印模式小于或等于 113,返回对象单个元素的字符串表示形式
        if _get_legacy_print_mode() <= 113:
            return str(self.item())
        # 否则调用父类的 __str__ 方法
        return super().__str__()

    def __getattribute__(self, attr):
        # 如果属性名为 'setfield', 'getfield', 'dtype' 中的一个,直接从父类获取该属性
        if attr in ('setfield', 'getfield', 'dtype'):
            return nt.void.__getattribute__(self, attr)
        try:
            # 否则尝试从父类获取属性
            return nt.void.__getattribute__(self, attr)
        except AttributeError:
            pass
        # 获取字段字典
        fielddict = nt.void.__getattribute__(self, 'dtype').fields
        # 尝试获取属性在字段字典中的信息
        res = fielddict.get(attr, None)
        if res:
            # 如果存在字段信息,获取字段值
            obj = self.getfield(*res[:2])
            # 如果字段值有子字段,则返回一个 record 类型的视图,否则返回字段值
            try:
                dt = obj.dtype
            except AttributeError:
                # 如果字段是 Object 类型,直接返回字段值
                return obj
            if dt.names is not None:
                return obj.view((self.__class__, obj.dtype))
            return obj
        else:
            # 如果字段信息不存在,抛出 AttributeError 异常
            raise AttributeError("'record' object has no "
                    "attribute '%s'" % attr)

    def __setattr__(self, attr, val):
        # 如果属性名为 'setfield', 'getfield', 'dtype' 中的一个,抛出 AttributeError 异常
        if attr in ('setfield', 'getfield', 'dtype'):
            raise AttributeError("Cannot set '%s' attribute" % attr)
        # 获取字段字典
        fielddict = nt.void.__getattribute__(self, 'dtype').fields
        # 尝试获取属性在字段字典中的信息
        res = fielddict.get(attr, None)
        if res:
            # 如果存在字段信息,设置字段值
            return self.setfield(val, *res[:2])
        else:
            # 如果字段信息不存在且属性存在,则设置属性值,否则抛出 AttributeError 异常
            if getattr(self, attr, None):
                return nt.void.__setattr__(self, attr, val)
            else:
                raise AttributeError("'record' object has no "
                        "attribute '%s'" % attr)

    def __getitem__(self, indx):
        # 获取指定索引位置的元素
        obj = nt.void.__getitem__(self, indx)

        # 复制 record.__getattribute__ 的行为
        if isinstance(obj, nt.void) and obj.dtype.names is not None:
            # 如果元素是 record 类型且有子字段,则返回一个 record 类型的视图
            return obj.view((self.__class__, obj.dtype))
        else:
            # 否则返回单个元素
            return obj

    def pprint(self):
        """Pretty-print all fields."""
        # 漂亮打印所有字段
        names = self.dtype.names
        # 计算字段名的最大长度
        maxlen = max(len(name) for name in names)
        fmt = '%% %ds: %%s' % maxlen
        # 格式化每个字段名及其值
        rows = [fmt % (name, getattr(self, name)) for name in names]
        # 将格式化后的字符串连接成一个字符串并返回
        return "\n".join(rows)
# 设置模块名称为 "numpy.rec"
@set_module("numpy.rec")
# 定义一个类 recarray,继承自 ndarray
class recarray(ndarray):
    """Construct an ndarray that allows field access using attributes.

    Arrays may have a data-types containing fields, analogous
    to columns in a spread sheet.  An example is ``[(x, int), (y, float)]``,
    where each entry in the array is a pair of ``(int, float)``.  Normally,
    these attributes are accessed using dictionary lookups such as ``arr['x']``
    and ``arr['y']``.  Record arrays allow the fields to be accessed as members
    of the array, using ``arr.x`` and ``arr.y``.

    Parameters
    ----------
    shape : tuple
        Shape of output array.
    dtype : data-type, optional
        The desired data-type.  By default, the data-type is determined
        from `formats`, `names`, `titles`, `aligned` and `byteorder`.
    formats : list of data-types, optional
        A list containing the data-types for the different columns, e.g.
        ``['i4', 'f8', 'i4']``.  `formats` does *not* support the new
        convention of using types directly, i.e. ``(int, float, int)``.
        Note that `formats` must be a list, not a tuple.
        Given that `formats` is somewhat limited, we recommend specifying
        `dtype` instead.
    names : tuple of str, optional
        The name of each column, e.g. ``('x', 'y', 'z')``.
    buf : buffer, optional
        By default, a new array is created of the given shape and data-type.
        If `buf` is specified and is an object exposing the buffer interface,
        the array will use the memory from the existing buffer.  In this case,
        the `offset` and `strides` keywords are available.

    Other Parameters
    ----------------
    titles : tuple of str, optional
        Aliases for column names.  For example, if `names` were
        ``('x', 'y', 'z')`` and `titles` is
        ``('x_coordinate', 'y_coordinate', 'z_coordinate')``, then
        ``arr['x']`` is equivalent to both ``arr.x`` and ``arr.x_coordinate``.
    byteorder : {'<', '>', '='}, optional
        Byte-order for all fields.
    aligned : bool, optional
        Align the fields in memory as the C-compiler would.
    strides : tuple of ints, optional
        Buffer (`buf`) is interpreted according to these strides (strides
        define how many bytes each array element, row, column, etc.
        occupy in memory).
    offset : int, optional
        Start reading buffer (`buf`) from this offset onwards.
    order : {'C', 'F'}, optional
        Row-major (C-style) or column-major (Fortran-style) order.

    Returns
    -------
    rec : recarray
        Empty array of the given shape and type.

    See Also
    --------
    numpy.rec.fromrecords : Construct a record array from data.
    numpy.record : fundamental data-type for `recarray`.
    numpy.rec.format_parser : determine data-type from formats, names, titles.

    Notes
    -----
    This constructor can be compared to ``empty``: it creates a new record
    """
    # 构造函数初始化
    def __init__(self, shape, dtype=None, formats=None, names=None,
                 buf=None, **kwargs):
        # 调用父类的构造函数,初始化数组
        super(recarray, self).__new__(recarray, shape, dtype, buffer=buf)
        # 如果指定了字段格式(formats)和字段名称(names),则设置相关属性
        if formats is not None and names is not None:
            # 确保 formats 是列表形式
            if not isinstance(formats, list):
                raise TypeError("formats must be a list")
            # 确保 names 是元组形式
            if not isinstance(names, tuple):
                raise TypeError("names must be a tuple")
            # 设置字段格式和名称
            self._fieldnames = names
            self._formats = formats

            # 确保字段格式和字段名称长度一致
            if len(self._fieldnames) != len(self._formats):
                raise ValueError("Length of formats and names must be equal")
        # 如果没有指定 dtype,则根据其他参数推断 dtype
        elif dtype is None:
            self._fieldnames = []
            self._formats = []
        # 如果没有指定 names,则抛出错误
        else:
            raise ValueError("Both formats and names must be specified if dtype is provided")

    def __setattr__(self, attr, value):
        # 如果属性名存在于字段名称中,设置属性值
        if attr in self._fieldnames:
            idx = self._fieldnames.index(attr)
            self[idx] = value
        else:
            # 否则,调用父类的属性设置方法
            super(recarray, self).__setattr__(attr, value)

    def __getattr__(self, attr):
        # 如果属性名存在于字段名称中,返回相应的值
        if attr in self._fieldnames:
            idx = self._fieldnames.index(attr)
            return self[idx]
        else:
            # 否则,调用父类的属性获取方法
            return super(recarray, self).__getattribute__(attr)

    def __getitem__(self, key):
        # 支持字段名和索引作为键值
        if isinstance(key, str):
            # 如果 key 是字符串,则返回对应字段的值
            if key in self._fieldnames:
                idx = self._fieldnames.index(key)
                return self[idx]
            else:
                raise KeyError(f"Field '{key}' not found in recarray")
        else:
            # 否则,调用父类的获取方法
            return super(recarray, self).__getitem__(key)

    def __setitem__(self, key, value):
        # 支持字段名和索引作为键值
        if isinstance(key, str):
            # 如果 key 是字符串,则设置对应字段的值
            if key in self._fieldnames:
                idx = self._fieldnames.index(key)
                self[idx] = value
            else:
                raise KeyError(f"Field '{key}' not found in recarray")
        else:
            # 否则,调用父类的设置方法
            super(recarray, self).__setitem__(key, value)

    def __reduce__(self):
        # 返回可序列化对象的元组表示
        pickled_state = super(recarray, self).__reduce__()
        new_state = pickled_state[2] + (self._fieldnames, self._formats)
        return pickled_state[0], pickled_state[1], new_state

    def __repr__(self):
        # 返回对象的字符串表示形式
        return "recarray(shape={}, dtype={}, formats={}, names={})".format(
            self.shape, self.dtype, self._formats, self._fieldnames)

    def __str__(self):
        # 返回对象的可打印字符串表示形式
        return self.__repr__()

# 设置模块名称为 "numpy.rec"
@set_module("numpy.rec")
# 定义一个类 recarray,继承自 ndarray
class recarray(ndarray):
    """Construct an ndarray that allows field access using attributes.

    Arrays may have a data-types containing fields, analogous
    to columns in a spread sheet.  An example is ``[(x, int), (y, float)]``,
    where each entry in the array is a pair of ``(int, float)``.  Normally,
    these attributes are accessed using dictionary lookups such as ``arr['x']``
    and ``arr['y']``.  Record arrays allow the fields to be accessed as members
    of the array, using ``arr.x`` and ``arr.y``.

    Parameters
    ----------
    shape : tuple
        Shape of output array.
    dtype : data-type, optional
        The desired data-type.  By default, the data-type is determined
        from `formats`, `names`, `titles`, `aligned` and `byteorder`.
    formats : list of data-types, optional
        A list containing the data-types for the different columns, e.g.
        ``['i4', 'f8', 'i4']``.  `formats` does *not* support the new
        convention of using types directly, i.e. ``(int, float, int)``.
        Note that `formats` must be a list, not a tuple.
        Given that `formats` is somewhat limited, we recommend specifying
        `dtype` instead.
    names : tuple of str, optional
        The name of each column, e.g. ``('x', 'y', 'z')``.
    buf : buffer, optional
        By default, a new array is created of the given shape and data-type.
        If `buf` is specified and is an object exposing the buffer interface,
        the array will use the memory from the existing buffer.  In this case,
        the `offset` and `strides` keywords are available.

    Other Parameters
    ----------------
    titles : tuple of str, optional
        Aliases for column names.  For example, if `names` were
        ``('x', 'y', 'z')`` and `titles` is
        ``('x_coordinate', 'y_coordinate', 'z_coordinate')``, then
        ``arr['x']`` is equivalent to both ``arr.x`` and ``arr.x_coordinate``.
    byteorder : {'<', '>', '='}, optional
        Byte-order for all fields.
    aligned : bool, optional
        Align the fields in memory as the C-compiler would.
    strides : tuple of ints, optional
        Buffer (`buf`) is interpreted according to these strides (strides
        define how many bytes each array element, row, column, etc.
        occupy in memory).
    offset : int, optional
        Start reading buffer (`buf`) from this offset onwards.
    order : {'C', 'F'}, optional
        Row-major (C-style) or column-major (Fortran-style) order.

    Returns
    -------
    rec : recarray
        Empty array of the given shape and type.

    See Also
    --------
    numpy.rec.fromrecords : Construct a record array from data.
    numpy.record : fundamental data-type for `recarray`.
    numpy.rec.format_parser : determine data-type from formats, names, titles.

    Notes
    -----
    This constructor can be compared to ``empty``: it creates a new record
    """
    # 构造函数初始化
    def __init__(self, shape, dtype=None, formats=None, names=None,
                 buf=None, **kwargs):
        # 调用父类的构造函数,初始化数组
        super(recarray, self).__new__(recarray, shape, dtype, buffer=buf)
        # 如果指定了字段格式(formats)和字段名称(names),则设置相关属性
        if formats is not None and names is not None:
            # 确保 formats 是列表形式
            if not isinstance(formats, list):
                raise TypeError("formats must be a list")
            # 确保 names 是元组形式
            if not isinstance(names, tuple):
                raise TypeError("names must be a tuple")
            # 设置字段格式和名称
            self._fieldnames = names
            self._formats = formats
            # 确保字段格式和字段名称长度一致
            if len(self._fieldnames) != len(self._formats):
                raise ValueError("Length of formats and names must be equal")
        # 如果没有指定 dtype,则根据其他参数推断 dtype
        elif dtype is None:
            self._fieldnames = []
            self._formats = []
        # 如果没有指定 names,则抛出错误
        else:
            raise ValueError("Both formats and names must be specified if dtype is provided")

    def __setattr__(self, attr, value):
        # 如果属性名存在于字段名称中,设置属性值
        if attr in self._fieldnames:
            idx = self._fieldnames.index(attr)
            self[idx] = value
        else:
            # 否则,调用父类的属性设置方法
            super(recarray, self).__setattr__(attr, value)

    def __getattr__(self, attr):
        # 如果属性名存在于字段名称中,返回相应的值
        if attr in self._fieldnames:
            idx = self._fieldnames.index(attr)
            return self[idx]
        else:
            # 否则,调用父类的属性获取方法
            return super(recarray, self).__getattribute__(attr)

    def __getitem__(self, key):
        # 支持字段名和索引作为键值
        if isinstance(key, str):
            # 如果 key 是字符串,则返回对应字段的值
            if key in self._fieldnames:
                idx = self._fieldnames.index(key)
                return self[idx]
            else:
                raise KeyError(f"Field '{key}' not found in recarray")
        else:
            # 否则,调用父类的获取方法
            return super(recarray, self).__getitem__(key)

    def __setitem__(self, key, value):
        # 支持字段名和索引作为键值
        if isinstance(key, str):
            # 如果 key 是字符串,则设置对应字段的值
            if key
    """
    Create a new subclass of ndarray for structured arrays, optionally filled
    with data from a buffer.

    Parameters
    ----------
    subtype : type
        The subclass type.
    shape : tuple
        Shape of the new array.
    dtype : dtype, optional
        Data type descriptor for the array. If not provided, it is inferred
        from other parameters.
    buf : buffer-like, optional
        Object exposing buffer interface for data storage.
    offset : int, optional
        Offset in bytes from the start of the buffer to the beginning of the
        array data.
    strides : tuple, optional
        Strides of the array data in memory.
    formats : sequence, optional
        Format descriptors for structured data.
    names : sequence, optional
        Names for the fields of structured data.
    titles : sequence, optional
        Titles for the fields of structured data.
    byteorder : {'=', '|', '>', '<', 'little', 'big'}, optional
        Byte order of the data. Default is native byte order.
    aligned : bool, optional
        Whether the data should be aligned.
    order : {'C', 'F'}, optional
        Whether to store multi-dimensional data in row-major (C-style) or
        column-major (Fortran-style) order.

    Returns
    -------
    self : ndarray
        A new instance of the structured array subclass.

    Notes
    -----
    This constructor initializes a structured array subclass similar to
    ndarray, but with additional support for structured data types. It can
    create an empty array structure or initialize it from provided data.

    See Also
    --------
    np.recarray : View a standard ndarray as a record array.
    """

    def __new__(subtype, shape, dtype=None, buf=None, offset=0, strides=None,
                formats=None, names=None, titles=None,
                byteorder=None, aligned=False, order='C'):
        """
        Create a new instance of the structured array subclass.

        Parameters
        ----------
        subtype : type
            The subclass type.
        shape : tuple
            Shape of the new array.
        dtype : dtype, optional
            Data type descriptor for the array. If not provided, it is inferred
            from other parameters.
        buf : buffer-like, optional
            Object exposing buffer interface for data storage.
        offset : int, optional
            Offset in bytes from the start of the buffer to the beginning of the
            array data.
        strides : tuple, optional
            Strides of the array data in memory.
        formats : sequence, optional
            Format descriptors for structured data.
        names : sequence, optional
            Names for the fields of structured data.
        titles : sequence, optional
            Titles for the fields of structured data.
        byteorder : {'=', '|', '>', '<', 'little', 'big'}, optional
            Byte order of the data. Default is native byte order.
        aligned : bool, optional
            Whether the data should be aligned.
        order : {'C', 'F'}, optional
            Whether to store multi-dimensional data in row-major (C-style) or
            column-major (Fortran-style) order.

        Returns
        -------
        self : ndarray
            A new instance of the structured array subclass.

        Notes
        -----
        This method is responsible for creating a new structured array
        instance based on the provided parameters. It initializes the array
        either from a specified buffer or as an empty structure if no buffer
        is provided.

        If `dtype` is specified, it converts it to a data type descriptor.
        If `buf` is provided, it initializes the array using the buffer's
        data.

        """
        if dtype is not None:
            descr = sb.dtype(dtype)  # Convert dtype to a structured dtype
        else:
            descr = format_parser(
                formats, names, titles, aligned, byteorder
            ).dtype  # Parse formats, names, titles to infer dtype

        if buf is None:
            self = ndarray.__new__(
                subtype, shape, (record, descr), order=order
            )  # Create ndarray instance without buffer
        else:
            self = ndarray.__new__(
                subtype, shape, (record, descr), buffer=buf,
                offset=offset, strides=strides, order=order
            )  # Create ndarray instance with buffer

        return self

    def __array_finalize__(self, obj):
        """
        Finalizes the creation of a structured array instance.

        Parameters
        ----------
        self : ndarray
            The newly created structured array instance.
        obj : ndarray or None
            An object from which the structured array instance was derived.

        Notes
        -----
        This method is called after the instance has been created and is
        responsible for finalizing its initialization. It checks if the
        dtype of the array is a record dtype and ensures that if it has
        names defined, it properly sets the dtype.

        If `self.dtype` is not a record dtype but has names, it invokes
        `__setattr__` to convert it to a record dtype.
        """
        if self.dtype.type is not record and self.dtype.names is not None:
            # Convert to a record dtype if dtype is not np.record
            self.dtype = self.dtype
    # 当尝试获取对象的属性时调用的特殊方法,用于获取对象的属性值
    def __getattribute__(self, attr):
        # 检查 ndarray 是否具有这个属性,并返回属性值(注意,如果字段与 ndarray 属性同名,将无法通过属性访问)
        try:
            return object.__getattribute__(self, attr)
        except AttributeError:  # 如果 attr 是字段名
            pass

        # 查找具有此名称的字段
        fielddict = ndarray.__getattribute__(self, 'dtype').fields
        try:
            # 获取字段的偏移量和数据类型
            res = fielddict[attr][:2]
        except (TypeError, KeyError) as e:
            # 抛出 AttributeError 如果没有找到对应的字段
            raise AttributeError("recarray has no attribute %s" % attr) from e
        # 获取字段的值
        obj = self.getfield(*res)

        # 在此时,obj 总是一个 recarray,因为(参见 PyArray_GetField)obj 的类型是继承的。
        # 如果 obj.dtype 是非结构化的,将其转换为 ndarray。
        # 如果 obj 是结构化的并且是 void 类型,则将其转换为相同的 dtype.type(例如保留 numpy.record 类型),
        # 因为嵌套的结构化字段不会继承类型。但是对于非 void 结构化类型,不执行此操作。
        if obj.dtype.names is not None:
            if issubclass(obj.dtype.type, nt.void):
                return obj.view(dtype=(self.dtype.type, obj.dtype))
            return obj
        else:
            return obj.view(ndarray)

    # 当尝试设置对象的属性时调用的特殊方法,用于设置对象的属性值
    def __setattr__(self, attr, val):

        # 自动将(void)结构化类型转换为记录类型
        # (但不包括非 void 结构、子数组或非结构化的 void)
        if (
            attr == 'dtype' and 
            issubclass(val.type, nt.void) and 
            val.names is not None
        ):
            val = sb.dtype((record, val))

        # 检查属性是否是新属性
        newattr = attr not in self.__dict__
        try:
            # 尝试设置属性值
            ret = object.__setattr__(self, attr, val)
        except Exception:
            # 获取字段字典或空字典
            fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
            if attr not in fielddict:
                # 如果属性不在字段字典中,则抛出异常
                raise
        else:
            fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
            if attr not in fielddict:
                # 如果属性不在字段字典中,返回设置结果
                return ret
            if newattr:
                # 如果是新属性或此 setattr 在内部属性上起作用
                try:
                    # 尝试删除新属性
                    object.__delattr__(self, attr)
                except Exception:
                    return ret
        try:
            # 获取字段的偏移量和数据类型
            res = fielddict[attr][:2]
        except (TypeError, KeyError) as e:
            # 抛出 AttributeError 如果没有找到对应的字段
            raise AttributeError(
                "record array has no attribute %s" % attr
            ) from e
        # 设置字段的值
        return self.setfield(val, *res)
    #`
    # 覆盖了父类的 __getitem__ 方法,根据索引获取元素
    def __getitem__(self, indx):
        # 调用父类的 __getitem__ 方法获取元素
        obj = super().__getitem__(indx)

        # 模仿 getattr 的行为,但这里可能返回单个元素
        if isinstance(obj, ndarray):  # 如果返回的是 ndarray 类型的对象
            if obj.dtype.names is not None:  # 如果 ndarray 具有字段名
                # 将 obj 视图转换为当前类的类型
                obj = obj.view(type(self))
                # 如果 obj 的 dtype 是 numpy.void 的子类
                if issubclass(obj.dtype.type, np.void):
                    # 返回一个新的视图,其 dtype 为 (self.dtype.type, obj.dtype)
                    return obj.view(dtype=(self.dtype.type, obj.dtype))
                return obj  # 返回转换后的 obj
            else:
                return obj.view(type=ndarray)  # 返回 obj 的 ndarray 视图
        else:
            # 返回单个元素
            return obj

    # 返回对象的字符串表示形式
    def __repr__(self):

        repr_dtype = self.dtype
        if (
            self.dtype.type is np.record or 
            not issubclass(self.dtype.type, np.void)
        ):
            # 如果是完整的记录数组(具有 numpy.record dtype),
            # 或者如果它具有标量(非 void)dtype 且没有记录,
            # 使用 rec.array 函数表示。由于 rec.array 会将 dtype 转换为 numpy.record,
            # 所以在打印前需要转换回非记录形式。
            if repr_dtype.type is np.record:
                repr_dtype = np.dtype((np.void, repr_dtype))
            prefix = "rec.array("
            fmt = 'rec.array(%s,%sdtype=%s)'
        else:
            # 否则使用 np.array 加一个视图表示
            # 这种情况只会在用户处理 dtype 时可能出现奇怪的情况。
            prefix = "array("
            fmt = 'array(%s,%sdtype=%s).view(numpy.recarray)'

        # 获取数据/形状的字符串表示。逻辑取自 numeric.array_repr
        if self.size > 0 or self.shape == (0,):
            lst = np.array2string(
                self, separator=', ', prefix=prefix, suffix=',')
        else:
            # 显示长度为零的形状,除非它是 (0,)
            lst = "[], shape=%s" % (repr(self.shape),)

        lf = '\n'+' '*len(prefix)
        if _get_legacy_print_mode() <= 113:
            lf = ' ' + lf  # 尾随空格
        return fmt % (lst, lf, repr_dtype)

    # 返回字段的值或设置字段的值
    def field(self, attr, val=None):
        if isinstance(attr, int):
            # 如果 attr 是整数,获取 dtype 的字段名
            names = ndarray.__getattribute__(self, 'dtype').names
            attr = names[attr]

        # 获取 dtype 的字段字典
        fielddict = ndarray.__getattribute__(self, 'dtype').fields

        # 获取字段的偏移量和形状
        res = fielddict[attr][:2]

        if val is None:
            # 如果 val 为 None,获取字段的值
            obj = self.getfield(*res)
            if obj.dtype.names is not None:
                return obj  # 如果 obj 具有字段名,返回 obj
            return obj.view(ndarray)  # 否则返回 obj 的 ndarray 视图
        else:
            # 否则设置字段的值并返回结果
            return self.setfield(val, *res)
def _deprecate_shape_0_as_None(shape):
    # 如果 shape 为 0,则发出未来警告,并返回 None
    if shape == 0:
        warnings.warn(
            "Passing `shape=0` to have the shape be inferred is deprecated, "
            "and in future will be equivalent to `shape=(0,)`. To infer "
            "the shape and suppress this warning, pass `shape=None` instead.",
            FutureWarning, stacklevel=3)
        return None
    else:
        # 否则直接返回 shape
        return shape


@set_module("numpy.rec")
def fromarrays(arrayList, dtype=None, shape=None, formats=None,
               names=None, titles=None, aligned=False, byteorder=None):
    """Create a record array from a (flat) list of arrays

    Parameters
    ----------
    arrayList : list or tuple
        List of array-like objects (such as lists, tuples,
        and ndarrays).
    dtype : data-type, optional
        valid dtype for all arrays
    shape : int or tuple of ints, optional
        Shape of the resulting array. If not provided, inferred from
        ``arrayList[0]``.
    formats, names, titles, aligned, byteorder :
        If `dtype` is ``None``, these arguments are passed to
        `numpy.rec.format_parser` to construct a dtype. See that function for
        detailed documentation.

    Returns
    -------
    np.recarray
        Record array consisting of given arrayList columns.

    Examples
    --------
    >>> x1=np.array([1,2,3,4])
    >>> x2=np.array(['a','dd','xyz','12'])
    >>> x3=np.array([1.1,2,3,4])
    >>> r = np.rec.fromarrays([x1,x2,x3],names='a,b,c')
    >>> print(r[1])
    (2, 'dd', 2.0) # may vary
    >>> x1[1]=34
    >>> r.a
    array([1, 2, 3, 4])

    >>> x1 = np.array([1, 2, 3, 4])
    >>> x2 = np.array(['a', 'dd', 'xyz', '12'])
    >>> x3 = np.array([1.1, 2, 3,4])
    >>> r = np.rec.fromarrays(
    ...     [x1, x2, x3],
    ...     dtype=np.dtype([('a', np.int32), ('b', 'S3'), ('c', np.float32)]))
    >>> r
    rec.array([(1, b'a', 1.1), (2, b'dd', 2. ), (3, b'xyz', 3. ),
               (4, b'12', 4. )],
              dtype=[('a', '<i4'), ('b', 'S3'), ('c', '<f4')])
    """

    arrayList = [sb.asarray(x) for x in arrayList]

    # NumPy 1.19.0, 2020-01-01
    # 调用 _deprecate_shape_0_as_None 函数,处理 shape 为 0 的情况
    shape = _deprecate_shape_0_as_None(shape)

    if shape is None:
        # 如果 shape 为 None,则从第一个数组推断出 shape
        shape = arrayList[0].shape
    elif isinstance(shape, int):
        # 如果 shape 是 int 类型,则转换为元组
        shape = (shape,)

    if formats is None and dtype is None:
        # 如果未提供 dtype,则通过遍历 arrayList 列表中的对象来确定 formats
        formats = [obj.dtype for obj in arrayList]

    if dtype is not None:
        # 如果提供了 dtype,则将其转换为 dtype 对象
        descr = sb.dtype(dtype)
    else:
        # 否则,通过 format_parser 函数获取 dtype 描述符
        descr = format_parser(formats, names, titles, aligned, byteorder).dtype
    _names = descr.names

    # 根据 dtype 的长度确定形状
    if len(descr) != len(arrayList):
        raise ValueError("mismatch between the number of fields "
                "and the number of arrays")

    d0 = descr[0].shape
    nn = len(d0)
    if nn > 0:
        shape = shape[:-nn]

    _array = recarray(shape, descr)
    # 遍历数组列表并填充记录数组(创建副本)
    for k, obj in enumerate(arrayList):
        # 获取描述符对象的维度
        nn = descr[k].ndim
        # 获取对象的形状,去掉描述符对象的维度后剩余的部分
        testshape = obj.shape[:obj.ndim - nn]
        # 获取当前对象的名称
        name = _names[k]
        # 检查当前对象的形状是否与整体形状相匹配
        if testshape != shape:
            # 如果形状不匹配,则抛出值错误异常
            raise ValueError(f'array-shape mismatch in array {k} ("{name}")')

        # 将当前对象存入记录数组中的对应名称位置
        _array[name] = obj

    # 返回填充后的记录数组
    return _array
# 设置函数的模块为 "numpy.rec"
@set_module("numpy.rec")
def fromrecords(recList, dtype=None, shape=None, formats=None, names=None,
                titles=None, aligned=False, byteorder=None):
    """从文本形式的记录列表创建一个 recarray。

    Parameters
    ----------
    recList : sequence
        包含记录的列表,可以是异构的数据 - 将会提升到最高的数据类型。
    dtype : data-type, optional
        所有数组的有效数据类型。
    shape : int or tuple of ints, optional
        每个数组的形状。
    formats, names, titles, aligned, byteorder :
        如果 `dtype` 是 ``None``,这些参数将传递给 `numpy.format_parser` 来构建数据类型。
        详细文档请参考该函数。

        如果 `formats` 和 `dtype` 都是 `None`,则会自动检测格式。使用元组列表而不是列表列表可以提高处理速度。

    Returns
    -------
    np.recarray
        包含给定 recList 行的记录数组。

    Examples
    --------
    >>> r=np.rec.fromrecords([(456,'dbe',1.2),(2,'de',1.3)],
    ... names='col1,col2,col3')
    >>> print(r[0])
    (456, 'dbe', 1.2)
    >>> r.col1
    array([456,   2])
    >>> r.col2
    array(['dbe', 'de'], dtype='<U3')
    >>> import pickle
    >>> pickle.loads(pickle.dumps(r))
    rec.array([(456, 'dbe', 1.2), (  2, 'de', 1.3)],
              dtype=[('col1', '<i8'), ('col2', '<U3'), ('col3', '<f8')])
    """

    if formats is None and dtype is None:  # 如果没有指定格式和数据类型,则执行以下代码(较慢的方式)
        # 将 recList 转换为对象数组
        obj = sb.array(recList, dtype=object)
        # 生成每列的数组列表
        arrlist = [
            sb.array(obj[..., i].tolist()) for i in range(obj.shape[-1])
        ]
        # 调用 fromarrays 函数,返回结果
        return fromarrays(arrlist, formats=formats, shape=shape, names=names,
                          titles=titles, aligned=aligned, byteorder=byteorder)

    if dtype is not None:
        # 如果指定了数据类型,则创建描述符
        descr = sb.dtype((record, dtype))
    else:
        # 否则,通过 format_parser 函数获取描述符
        descr = format_parser(
            formats, names, titles, aligned, byteorder
        ).dtype

    try:
        # 尝试使用描述符创建数组
        retval = sb.array(recList, dtype=descr)
    except (TypeError, ValueError):
        # 处理可能的类型错误或数值错误
        shape = _deprecate_shape_0_as_None(shape)
        if shape is None:
            shape = len(recList)
        if isinstance(shape, int):
            shape = (shape,)
        if len(shape) > 1:
            raise ValueError("Can only deal with 1-d array.")
        # 创建 recarray 对象并填充数据
        _array = recarray(shape, descr)
        for k in range(_array.size):
            _array[k] = tuple(recList[k])
        # 提出警告,因为传入的可能是列表列表而不是列表元组
        warnings.warn(
            "fromrecords expected a list of tuples, may have received a list "
            "of lists instead. In the future that will raise an error",
            FutureWarning, stacklevel=2)
        return _array
    else:
        # 如果指定了形状且结果数组的形状与之不同,则修改形状
        if shape is not None and retval.shape != shape:
            retval.shape = shape

    # 将结果数组视图转换为 recarray 类型并返回
    res = retval.view(recarray)

    return res


@set_module("numpy.rec")
# 创建一个从二进制数据中生成记录数组的函数
def fromstring(datastring, dtype=None, shape=None, offset=0, formats=None,
               names=None, titles=None, aligned=False, byteorder=None):
    r"""Create a record array from binary data

    Note that despite the name of this function it does not accept `str`
    instances.

    Parameters
    ----------
    datastring : bytes-like
        Buffer of binary data
    dtype : data-type, optional
        Valid dtype for all arrays
    shape : int or tuple of ints, optional
        Shape of each array.
    offset : int, optional
        Position in the buffer to start reading from.
    formats, names, titles, aligned, byteorder :
        If `dtype` is ``None``, these arguments are passed to
        `numpy.format_parser` to construct a dtype. See that function for
        detailed documentation.

    Returns
    -------
    np.recarray
        Record array view into the data in datastring. This will be readonly
        if `datastring` is readonly.

    See Also
    --------
    numpy.frombuffer

    Examples
    --------
    >>> a = b'\x01\x02\x03abc'
    >>> np.rec.fromstring(a, dtype='u1,u1,u1,S3')
    rec.array([(1, 2, 3, b'abc')],
            dtype=[('f0', 'u1'), ('f1', 'u1'), ('f2', 'u1'), ('f3', 'S3')])

    >>> grades_dtype = [('Name', (np.str_, 10)), ('Marks', np.float64),
    ...                 ('GradeLevel', np.int32)]
    >>> grades_array = np.array([('Sam', 33.3, 3), ('Mike', 44.4, 5),
    ...                         ('Aadi', 66.6, 6)], dtype=grades_dtype)
    >>> np.rec.fromstring(grades_array.tobytes(), dtype=grades_dtype)
    rec.array([('Sam', 33.3, 3), ('Mike', 44.4, 5), ('Aadi', 66.6, 6)],
            dtype=[('Name', '<U10'), ('Marks', '<f8'), ('GradeLevel', '<i4')])

    >>> s = '\x01\x02\x03abc'
    >>> np.rec.fromstring(s, dtype='u1,u1,u1,S3')
    Traceback (most recent call last):
       ...
    TypeError: a bytes-like object is required, not 'str'
    """

    # 如果未提供 dtype 和 formats 参数,则抛出 TypeError 异常
    if dtype is None and formats is None:
        raise TypeError("fromstring() needs a 'dtype' or 'formats' argument")

    # 使用 dtype 参数创建描述符
    if dtype is not None:
        descr = sb.dtype(dtype)
    else:
        descr = format_parser(formats, names, titles, aligned, byteorder).dtype

    # 计算每个记录的字节大小
    itemsize = descr.itemsize

    # 处理 NumPy 1.19.0 中的 shape 参数
    shape = _deprecate_shape_0_as_None(shape)

    # 如果 shape 参数为 None 或 -1,则根据数据长度和偏移计算 shape
    if shape in (None, -1):
        shape = (len(datastring) - offset) // itemsize

    # 创建记录数组对象并返回
    _array = recarray(shape, descr, buf=datastring, offset=offset)
    return _array

# 获取文件对象中剩余的字节数
def get_remaining_size(fd):
    # 记录当前文件指针位置
    pos = fd.tell()
    try:
        # 将文件指针移到文件末尾并计算文件总大小
        fd.seek(0, 2)
        return fd.tell() - pos  # 返回剩余的字节数
    finally:
        # 恢复文件指针到原始位置
        fd.seek(pos, 0)

@set_module("numpy.rec")
def fromfile(fd, dtype=None, shape=None, offset=0, formats=None,
             names=None, titles=None, aligned=False, byteorder=None):
    """Create an array from binary file data

    Parameters
    ----------
    fd : file-like object
        File object containing binary data
    dtype : data-type, optional
        Valid dtype for all arrays
    shape : int or tuple of ints, optional
        Shape of each array.
    offset : int, optional
        Position in the file to start reading from.
    formats, names, titles, aligned, byteorder :
        If `dtype` is ``None``, these arguments are passed to
        `numpy.format_parser` to construct a dtype. See that function for
        detailed documentation.

    """
    fd : str or file type
        # 参数fd可以是字符串或文件对象,如果是字符串或路径对象,则会打开文件;否则假定它是文件对象。
        # 文件对象必须支持随机访问(即必须具有tell和seek方法)。

    dtype : data-type, optional
        # 数据类型,可选参数。

    shape : int or tuple of ints, optional
        # 数组的形状,可以是整数或整数元组,可选参数。

    offset : int, optional
        # 文件中开始读取的位置,可选参数。

    formats, names, titles, aligned, byteorder :
        # 如果`dtype`为None,则这些参数会传递给`numpy.format_parser`来构造dtype。
        # 参见该函数的详细文档说明。

    Returns
    -------
    np.recarray
        # 返回一个包含文件中数据的记录数组。

    Examples
    --------
    >>> from tempfile import TemporaryFile
    >>> a = np.empty(10,dtype='f8,i4,a5')
    >>> a[5] = (0.5,10,'abcde')
    >>>
    >>> fd=TemporaryFile()
    >>> a = a.view(a.dtype.newbyteorder('<'))
    >>> a.tofile(fd)
    >>>
    >>> _ = fd.seek(0)
    >>> r=np.rec.fromfile(fd, formats='f8,i4,a5', shape=10,
    ... byteorder='<')
    >>> print(r[5])
    (0.5, 10, b'abcde')
    >>> r.shape
    (10,)
    """

    if dtype is None and formats is None:
        raise TypeError("fromfile() needs a 'dtype' or 'formats' argument")

    # NumPy 1.19.0, 2020-01-01
    shape = _deprecate_shape_0_as_None(shape)
        # 使用_deprecate_shape_0_as_None函数处理shape参数,将形状为0的情况处理为None。

    if shape is None:
        shape = (-1,)
    elif isinstance(shape, int):
        shape = (shape,)
        # 如果shape为None,则设置为(-1,);如果shape是整数,则转换为元组。

    if hasattr(fd, 'readinto'):
        # GH issue 2504. fd supports io.RawIOBase or io.BufferedIOBase
        # interface. Example of fd: gzip, BytesIO, BufferedReader
        # file already opened
        ctx = nullcontext(fd)
        # 如果fd支持io.RawIOBase或io.BufferedIOBase接口,则使用nullcontext来创建上下文。
    else:
        # open file
        ctx = open(os.fspath(fd), 'rb')
        # 否则,通过os.fspath将fd转换为路径字符串,并以二进制只读模式打开文件。

    with ctx as fd:
        if offset > 0:
            fd.seek(offset, 1)
            # 如果offset大于0,则在文件中移动读取位置。

        size = get_remaining_size(fd)
        # 获取文件中剩余的字节数。

        if dtype is not None:
            descr = sb.dtype(dtype)
            # 如果dtype不为None,则使用sb.dtype处理dtype参数。
        else:
            descr = format_parser(
                formats, names, titles, aligned, byteorder
            ).dtype
            # 否则,使用format_parser函数根据formats、names、titles、aligned、byteorder构造dtype。

        itemsize = descr.itemsize
        # 获取dtype的每个元素的字节大小。

        shapeprod = sb.array(shape).prod(dtype=nt.intp)
        # 计算shape中所有元素的乘积,并将结果的数据类型设为nt.intp。

        shapesize = shapeprod * itemsize
        # 计算总的形状大小(字节数)。

        if shapesize < 0:
            shape = list(shape)
            shape[shape.index(-1)] = size // -shapesize
            shape = tuple(shape)
            shapeprod = sb.array(shape).prod(dtype=nt.intp)
            # 如果shapesize小于0,则根据文件中剩余的字节数调整shape的值。

        nbytes = shapeprod * itemsize
        # 计算总的字节数。

        if nbytes > size:
            raise ValueError(
                    "Not enough bytes left in file for specified "
                    "shape and type."
                )
            # 如果需要读取的字节数大于文件中剩余的字节数,则引发ValueError异常。

        # create the array
        _array = recarray(shape, descr)
        # 创建一个形状为shape、数据类型为descr的记录数组。

        nbytesread = fd.readinto(_array.data)
        # 将文件中的数据读取到记录数组的数据部分。

        if nbytesread != nbytes:
            raise OSError("Didn't read as many bytes as expected")
            # 如果实际读取的字节数与预期的不符,则引发OSError异常。

    return _array
# 设置模块名称为 "numpy.rec"
@set_module("numpy.rec")
# 定义一个名为 array 的函数,用于构建记录数组
def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None,
          names=None, titles=None, aligned=False, byteorder=None, copy=True):
    """
    Construct a record array from a wide-variety of objects.

    A general-purpose record array constructor that dispatches to the
    appropriate `recarray` creation function based on the inputs (see Notes).

    Parameters
    ----------
    obj : any
        Input object. See Notes for details on how various input types are
        treated.
    dtype : data-type, optional
        Valid dtype for array.
    shape : int or tuple of ints, optional
        Shape of each array.
    offset : int, optional
        Position in the file or buffer to start reading from.
    strides : tuple of ints, optional
        Buffer (`buf`) is interpreted according to these strides (strides
        define how many bytes each array element, row, column, etc.
        occupy in memory).
    formats, names, titles, aligned, byteorder :
        If `dtype` is ``None``, these arguments are passed to
        `numpy.format_parser` to construct a dtype. See that function for
        detailed documentation.
    copy : bool, optional
        Whether to copy the input object (True), or to use a reference instead.
        This option only applies when the input is an ndarray or recarray.
        Defaults to True.

    Returns
    -------
    np.recarray
        Record array created from the specified object.

    Notes
    -----
    If `obj` is ``None``, then call the `~numpy.recarray` constructor. If
    `obj` is a string, then call the `fromstring` constructor. If `obj` is a
    list or a tuple, then if the first object is an `~numpy.ndarray`, call
    `fromarrays`, otherwise call `fromrecords`. If `obj` is a
    `~numpy.recarray`, then make a copy of the data in the recarray
    (if ``copy=True``) and use the new formats, names, and titles. If `obj`
    is a file, then call `fromfile`. Finally, if obj is an `ndarray`, then
    return ``obj.view(recarray)``, making a copy of the data if ``copy=True``.

    Examples
    --------
    >>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    >>> a
    array([[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]])

    >>> np.rec.array(a)
    rec.array([[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]],
              dtype=int64)

    >>> b = [(1, 1), (2, 4), (3, 9)]
    >>> c = np.rec.array(b, formats = ['i2', 'f2'], names = ('x', 'y'))
    >>> c
    rec.array([(1, 1.), (2, 4.), (3, 9.)],
              dtype=[('x', '<i2'), ('y', '<f2')])

    >>> c.x
    array([1, 2, 3], dtype=int16)

    >>> c.y
    array([1.,  4.,  9.], dtype=float16)

    >>> r = np.rec.array(['abc','def'], names=['col1','col2'])
    >>> print(r.col1)
    abc

    >>> r.col1
    array('abc', dtype='<U3')

    >>> r.col2
    array('def', dtype='<U3')
    """
    # 检查对象是否为None、字符串或具有'readinto'属性,并且formats和dtype都未定义时,抛出值错误异常
    if ((isinstance(obj, (type(None), str)) or hasattr(obj, 'readinto')) and
           formats is None and dtype is None):
        raise ValueError("Must define formats (or dtype) if object is "
                         "None, string, or an open file")

    # 初始化一个空字典用于存储关键字参数
    kwds = {}

    # 如果定义了dtype,则将其转换为dtype对象
    if dtype is not None:
        dtype = sb.dtype(dtype)
    
    # 如果formats不为None,则使用format_parser函数解析formats参数,并获取其dtype
    elif formats is not None:
        dtype = format_parser(formats, names, titles,
                              aligned, byteorder).dtype
    
    # 如果formats和dtype都未定义,则将关键字参数设置为包含这些参数的字典
    else:
        kwds = {'formats': formats,
                'names': names,
                'titles': titles,
                'aligned': aligned,
                'byteorder': byteorder
                }

    # 如果obj为None,则根据指定的shape创建一个recarray对象,使用给定的dtype、buf、offset和strides参数
    if obj is None:
        if shape is None:
            raise ValueError("Must define a shape if obj is None")
        return recarray(shape, dtype, buf=obj, offset=offset, strides=strides)

    # 如果obj是字节串,则调用fromstring函数解析为数组对象,使用给定的dtype、shape和kwds参数
    elif isinstance(obj, bytes):
        return fromstring(obj, dtype, shape=shape, offset=offset, **kwds)

    # 如果obj是列表或元组,则根据其第一个元素的类型判断调用fromrecords或fromarrays函数,使用给定的dtype、shape和kwds参数
    elif isinstance(obj, (list, tuple)):
        if isinstance(obj[0], (tuple, list)):
            return fromrecords(obj, dtype=dtype, shape=shape, **kwds)
        else:
            return fromarrays(obj, dtype=dtype, shape=shape, **kwds)

    # 如果obj是recarray类型,则根据情况进行视图转换和复制操作,并返回新的对象
    elif isinstance(obj, recarray):
        if dtype is not None and (obj.dtype != dtype):
            new = obj.view(dtype)
        else:
            new = obj
        if copy:
            new = new.copy()
        return new

    # 如果obj具有'readinto'属性,则调用fromfile函数从文件对象创建数组对象,使用给定的dtype、shape和offset参数
    elif hasattr(obj, 'readinto'):
        return fromfile(obj, dtype=dtype, shape=shape, offset=offset)

    # 如果obj是ndarray类型,则根据情况进行视图转换和复制操作,并返回新的recarray视图对象
    elif isinstance(obj, ndarray):
        if dtype is not None and (obj.dtype != dtype):
            new = obj.view(dtype)
        else:
            new = obj
        if copy:
            new = new.copy()
        return new.view(recarray)

    # 对于其他情况,尝试获取obj的__array_interface__属性,如果未定义或者不是字典类型,则抛出值错误异常
    else:
        interface = getattr(obj, "__array_interface__", None)
        if interface is None or not isinstance(interface, dict):
            raise ValueError("Unknown input type")
        # 将obj转换为数组对象,并根据情况进行视图转换操作,返回recarray视图对象
        obj = sb.array(obj)
        if dtype is not None and (obj.dtype != dtype):
            obj = obj.view(dtype)
        return obj.view(recarray)