NumPy-源码解析-四十七-

73 阅读1小时+

NumPy 源码解析(四十七)

.\numpy\numpy\_core\code_generators\verify_c_api_version.py

#!/usr/bin/env python3
# 导入必要的库
import os
import sys
import argparse

# 自定义异常类,用于处理 C API 版本不匹配的情况
class MismatchCAPIError(ValueError):
    pass

# 获取当前 C API 的哈希值和记录的哈希值
def get_api_versions(apiversion):
    """
    Return current C API checksum and the recorded checksum.

    Return current C API checksum and the recorded checksum for the given
    version of the C API version.

    """
    # 将当前文件的路径添加到系统路径中
    sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
    try:
        # 导入 genapi 模块
        m = __import__('genapi')
        # 导入 numpy_api 模块
        numpy_api = __import__('numpy_api')
        # 计算当前完整 API 的哈希值
        curapi_hash = m.fullapi_hash(numpy_api.full_api)
        # 获取已记录的各个 API 版本的哈希值
        apis_hash = m.get_versions_hash()
    finally:
        # 删除添加的路径,恢复原始状态
        del sys.path[0]

    return curapi_hash, apis_hash[apiversion]

# 检查指定的 C API 版本是否需要更新
def check_api_version(apiversion):
    """Emits a MismatchCAPIWarning if the C API version needs updating."""
    # 获取当前 C API 的哈希值和记录的哈希值
    curapi_hash, api_hash = get_api_versions(apiversion)

    # 如果当前哈希值和记录的哈希值不同,则抛出异常
    if not curapi_hash == api_hash:
        msg = ("API mismatch detected, the C API version "
               "numbers have to be updated. Current C api version is "
               f"{apiversion}, with checksum {curapi_hash}, but recorded "
               f"checksum in _core/codegen_dir/cversions.txt is {api_hash}. "
               "If functions were added in the C API, you have to update "
               f"C_API_VERSION in {__file__}."
               )
        raise MismatchCAPIError(msg)

# 主函数,解析命令行参数并调用检查 API 版本的函数
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--api-version",
        type=str,
        help="C API version to verify (as a hex string)"
    )
    args = parser.parse_args()

    check_api_version(int(args.api_version, base=16))

# 如果作为脚本直接执行,则调用主函数
if __name__ == "__main__":
    main()

.\numpy\numpy\_core\code_generators\__init__.py

# 导入必要的模块:os(操作系统接口)、shutil(高级文件操作)、datetime(日期和时间相关操作)
import os
import shutil
import datetime

# 定义一个函数,接收两个参数:source_dir(源目录)和dest_dir(目标目录)
def backup_files(source_dir, dest_dir):
    # 使用当前日期和时间生成一个唯一的备份文件夹名
    backup_dir = os.path.join(dest_dir, datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S'))
    
    # 创建备份目录
    os.makedirs(backup_dir)
    
    # 遍历源目录中的所有文件和文件夹
    for root, dirs, files in os.walk(source_dir):
        for file in files:
            # 构建每个文件的源路径和目标路径
            source_file = os.path.join(root, file)
            dest_file = os.path.join(backup_dir, os.path.relpath(source_file, source_dir))
            
            # 如果目标路径不存在,创建它
            if not os.path.exists(os.path.dirname(dest_file)):
                os.makedirs(os.path.dirname(dest_file))
            
            # 复制源文件到目标位置
            shutil.copy(source_file, dest_file)
    
    # 返回备份文件夹的路径
    return backup_dir

.\numpy\numpy\_core\cversions.py

"""Simple script to compute the api hash of the current API.

The API has is defined by numpy_api_order and ufunc_api_order.

"""

# 从 os.path 模块中导入 dirname 函数
from os.path import dirname

# 从 code_generators.genapi 模块中导入 fullapi_hash 函数
from code_generators.genapi import fullapi_hash
# 从 code_generators.numpy_api 模块中导入 full_api 对象
from code_generators.numpy_api import full_api

# 如果当前脚本被直接执行
if __name__ == '__main__':
    # 获取当前文件所在目录的路径
    curdir = dirname(__file__)
    # 打印计算出的当前 API 的哈希值
    print(fullapi_hash(full_api))

.\numpy\numpy\_core\defchararray.py

"""
This module contains a set of functions for vectorized string
operations and methods.

.. note::
   The `chararray` class exists for backwards compatibility with
   Numarray, it is not recommended for new development. Starting from numpy
   1.4, if one needs arrays of strings, it is recommended to use arrays of
   `dtype` `object_`, `bytes_` or `str_`, and use the free functions
   in the `numpy.char` module for fast vectorized string operations.
   
一些方法只有在你的 Python 版本中相应的字符串方法可用时才有效。

`defchararray` 的首选别名是 `numpy.char`。
"""
import functools  # 导入 functools 模块

import numpy as np  # 导入 numpy 模块
from .._utils import set_module  # 从上层目录的 _utils 模块中导入 set_module 函数
from .numerictypes import bytes_, str_, character  # 从 numerictypes 模块中导入 bytes_, str_, character 类
from .numeric import ndarray, array as narray, asarray as asnarray  # 从 numeric 模块中导入 ndarray, narray, asnarray 函数
from numpy._core.multiarray import compare_chararrays  # 从 numpy._core.multiarray 模块中导入 compare_chararrays 函数
from numpy._core import overrides  # 从 numpy._core 模块中导入 overrides 函数
from numpy.strings import *  # 导入 numpy.strings 中的所有方法
from numpy.strings import (  # 导入 numpy.strings 中的 multiply, partition, rpartition 方法
    multiply as strings_multiply,
    partition as strings_partition,
    rpartition as strings_rpartition,
)
from numpy._core.strings import (  # 从 numpy._core.strings 模块中导入 _split, _rsplit, _splitlines, _join 函数
    _split as split,
    _rsplit as rsplit,
    _splitlines as splitlines,
    _join as join,
)

__all__ = [  # 定义 __all__ 列表
    'equal', 'not_equal', 'greater_equal', 'less_equal',
    'greater', 'less', 'str_len', 'add', 'multiply', 'mod', 'capitalize',
    'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs',
    'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace',
    'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition',
    'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit',
    'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase',
    'title', 'translate', 'upper', 'zfill', 'isnumeric', 'isdecimal',
    'array', 'asarray', 'compare_chararrays', 'chararray'
    ]  # 定义包含所有方法和属性的 __all__ 列表

array_function_dispatch = functools.partial(  # 定义 array_function_dispatch 函数
    overrides.array_function_dispatch, module='numpy.char')  # 从 overrides 模块中导入 array_function_dispatch 函数

def _binary_op_dispatcher(x1, x2):
    return (x1, x2)  # 返回元组 (x1, x2)

@array_function_dispatch(_binary_op_dispatcher)  # 根据 array_function_dispatch 装饰器调用 _binary_op_dispatcher 函数
def equal(x1, x2):
    """
    Return (x1 == x2) element-wise.

    Unlike `numpy.equal`, this comparison is performed by first
    stripping whitespace characters from the end of the string.  This
    behavior is provided for backward-compatibility with numarray.

    Parameters
    ----------
    x1, x2 : array_like of str or unicode
        Input arrays of the same shape.

    Returns
    -------
    out : ndarray
        Output array of bools.

    Examples
    --------
    >>> y = "aa "
    >>> x = "aa"
    >>> np.char.equal(x, y)
    array(True)    

    See Also
    --------
    not_equal, greater_equal, less_equal, greater, less
    """
    return compare_chararrays(x1, x2, '==', True)  # 返回比较结果所得到的数组

@array_function_dispatch(_binary_op_dispatcher)  # 根据 array_function_dispatch 装饰器调用 _binary_op_dispatcher 函数
def not_equal(x1, x2):
    """
    Return (x1 != x2) element-wise.

    Unlike `numpy.not_equal`, this comparison is performed by first
    stripping whitespace characters from the end of the string.  This
    behavior is provided for backward-compatibility with numarray.
    
    Parameters
    ----------
    x1, x2 : array_like of str or unicode
        Input arrays of the same shape.
        
    Returns
    -------
    out : ndarray
        Output array of bools.
        
    See Also
    --------
    equal, greater_equal, less_equal, greater, less
    
    Examples
    --------
    >>> x1 = np.array(['a', 'b', 'c'])
    >>> np.char.not_equal(x1, 'b')
    array([ True, False,  True])
    
    """
    # 使用 compare_chararrays 函数比较两个字符串数组 x1 和 x2 的不等性,返回布尔类型的数组
    return compare_chararrays(x1, x2, '!=', True)
# 使用 array_function_dispatch 装饰器将函数注册到二进制操作调度器中
@array_function_dispatch(_binary_op_dispatcher)
# 定义函数 greater_equal,用于比较两个数组中元素是否 x1 >= x2,返回布尔值数组
def greater_equal(x1, x2):
    """
    Return (x1 >= x2) element-wise.

    Unlike `numpy.greater_equal`, this comparison is performed by
    first stripping whitespace characters from the end of the string.
    This behavior is provided for backward-compatibility with
    numarray.

    Parameters
    ----------
    x1, x2 : array_like of str or unicode
        Input arrays of the same shape.

    Returns
    -------
    out : ndarray
        Output array of bools.

    See Also
    --------
    equal, not_equal, less_equal, greater, less

    Examples
    --------
    >>> x1 = np.array(['a', 'b', 'c'])
    >>> np.char.greater_equal(x1, 'b')
    array([False,  True,  True])
    
    """
    # 调用 compare_chararrays 函数,比较 x1 和 x2 的字符数组,采用 '>=' 操作符,返回结果
    return compare_chararrays(x1, x2, '>=', True)


@array_function_dispatch(_binary_op_dispatcher)
# 定义函数 less_equal,用于比较两个数组中元素是否 x1 <= x2,返回布尔值数组
def less_equal(x1, x2):
    """
    Return (x1 <= x2) element-wise.

    Unlike `numpy.less_equal`, this comparison is performed by first
    stripping whitespace characters from the end of the string.  This
    behavior is provided for backward-compatibility with numarray.

    Parameters
    ----------
    x1, x2 : array_like of str or unicode
        Input arrays of the same shape.

    Returns
    -------
    out : ndarray
        Output array of bools.

    See Also
    --------
    equal, not_equal, greater_equal, greater, less

    Examples
    --------
    >>> x1 = np.array(['a', 'b', 'c'])
    >>> np.char.less_equal(x1, 'b')
    array([ True,  True, False])
    
    """
    # 调用 compare_chararrays 函数,比较 x1 和 x2 的字符数组,采用 '<=' 操作符,返回结果
    return compare_chararrays(x1, x2, '<=', True)


@array_function_dispatch(_binary_op_dispatcher)
# 定义函数 greater,用于比较两个数组中元素是否 x1 > x2,返回布尔值数组
def greater(x1, x2):
    """
    Return (x1 > x2) element-wise.

    Unlike `numpy.greater`, this comparison is performed by first
    stripping whitespace characters from the end of the string.  This
    behavior is provided for backward-compatibility with numarray.

    Parameters
    ----------
    x1, x2 : array_like of str or unicode
        Input arrays of the same shape.

    Returns
    -------
    out : ndarray
        Output array of bools.

    See Also
    --------
    equal, not_equal, greater_equal, less_equal, less
    
    Examples
    --------
    >>> x1 = np.array(['a', 'b', 'c'])
    >>> np.char.greater(x1, 'b')
    array([False, False,  True])
    
    """
    # 调用 compare_chararrays 函数,比较 x1 和 x2 的字符数组,采用 '>' 操作符,返回结果
    return compare_chararrays(x1, x2, '>', True)


@array_function_dispatch(_binary_op_dispatcher)
# 定义函数 less,用于比较两个数组中元素是否 x1 < x2,返回布尔值数组
def less(x1, x2):
    """
    Return (x1 < x2) element-wise.

    Unlike `numpy.greater`, this comparison is performed by first
    stripping whitespace characters from the end of the string.  This
    behavior is provided for backward-compatibility with numarray.

    Parameters
    ----------
    x1, x2 : array_like of str or unicode
        Input arrays of the same shape.

    Returns
    -------
    out : ndarray
        Output array of bools.

    See Also
    --------
    equal, not_equal, greater_equal, less_equal, greater

    Examples
    --------

    """
    # 调用 compare_chararrays 函数,比较 x1 和 x2 的字符数组,采用 '<' 操作符,返回结果
    return compare_chararrays(x1, x2, '<', True)
    # 创建一个包含字符串数组 ['a', 'b', 'c'] 的 NumPy 数组 x1
    x1 = np.array(['a', 'b', 'c'])
    # 使用 NumPy 的 char.less 函数比较 x1 中的每个元素是否小于 'b',返回布尔数组
    np.char.less(x1, 'b')
    array([True, False, False])
    
    # 调用一个未在当前上下文中定义的函数 compare_chararrays,传入参数 x1, x2, '<', True
    # 该函数似乎用于比较两个字符数组,返回结果可能是两个数组的比较结果
    return compare_chararrays(x1, x2, '<', True)
def multiply(a, i):
    """
    Return (a * i), that is string multiple concatenation,
    element-wise.

    Values in ``i`` of less than 0 are treated as 0 (which yields an
    empty string).

    Parameters
    ----------
    a : array_like, with `np.bytes_` or `np.str_` dtype
        Input array of strings or bytes.

    i : array_like, with any integer dtype
        Multiplier array. Each element specifies how many times
        to repeat the corresponding element in `a`.

    Returns
    -------
    out : ndarray
        Output array of str or unicode, depending on input types.
        The shape of `out` matches the shape of `a`.

    Notes
    -----
    This function is a wrapper around np.strings.multiply and raises
    ValueError if `i` contains non-integer values.

    Examples
    --------
    >>> a = np.array(["a", "b", "c"])
    >>> np.strings.multiply(a, 3)
    array(['aaa', 'bbb', 'ccc'], dtype='<U3')
    >>> i = np.array([1, 2, 3])
    >>> np.strings.multiply(a, i)
    array(['a', 'bb', 'ccc'], dtype='<U3')
    >>> np.strings.multiply(np.array(['a']), i)
    array(['a', 'aa', 'aaa'], dtype='<U3')
    >>> a = np.array(['a', 'b', 'c', 'd', 'e', 'f']).reshape((2, 3))
    >>> np.strings.multiply(a, 3)
    array([['aaa', 'bbb', 'ccc'],
           ['ddd', 'eee', 'fff']], dtype='<U3')
    >>> np.strings.multiply(a, i)
    array([['a', 'bb', 'ccc'],
           ['d', 'ee', 'fff']], dtype='<U3')

    """
    try:
        # Call np.strings.multiply to perform element-wise string multiplication
        return strings_multiply(a, i)
    except TypeError:
        # Raise ValueError if `i` contains non-integer values
        raise ValueError("Can only multiply by integers")


def partition(a, sep):
    """
    Partition each element in `a` around `sep`.

    Calls :meth:`str.partition` element-wise.

    For each element in `a`, split the element as the first
    occurrence of `sep`, and return 3 strings containing the part
    before the separator, the separator itself, and the part after
    the separator. If the separator is not found, return 3 strings
    containing the string itself, followed by two empty strings.

    Parameters
    ----------
    a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
        Input array containing strings or bytes.
    sep : {str, unicode}
        Separator to split each string element in `a`.

    Returns
    -------
    out : ndarray
        Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
        depending on input types. The output array will have an extra
        dimension with 3 elements per input element.

    Examples
    --------
    >>> x = np.array(["Numpy is nice!"])
    >>> np.char.partition(x, " ")
    array([['Numpy', ' ', 'is nice!']], dtype='<U8')
    
    See Also
    --------
    str.partition

    """
    # Use np.stack to partition each element of `a` around `sep` and stack the results
    return np.stack(strings_partition(a, sep), axis=-1)


def rpartition(a, sep):
    """
    Partition (split) each element around the right-most separator.

    Calls :meth:`str.rpartition` element-wise.

    For each element in `a`, split the element as the last
    occurrence of `sep`, and return 3 strings containing the part
    before the separator, the separator itself, and the part after
    the separator. If the separator is not found, return 3 strings
    containing the entire string followed by two empty strings.

    Parameters
    ----------
    a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
        Input array containing strings or bytes.
    sep : {str, unicode}
        Separator to split each string element in `a`.

    Returns
    -------
    out : ndarray
        Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
        depending on input types. The output array will have an extra
        dimension with 3 elements per input element.

    """
    # 使用 np.stack 将字符串数组 a 中每个元素根据右边最后出现的分隔符 sep 进行分割,并将结果堆叠成一个多维数组
    return np.stack(strings_rpartition(a, sep), axis=-1)
# 设置模块名为 "numpy.char"
@set_module("numpy.char")
# 定义 chararray 类,继承自 ndarray 类
class chararray(ndarray):
    """
    chararray(shape, itemsize=1, unicode=False, buffer=None, offset=0,
              strides=None, order=None)

    Provides a convenient view on arrays of string and unicode values.

    .. note::
       The `chararray` class exists for backwards compatibility with
       Numarray, it is not recommended for new development. Starting from numpy
       1.4, if one needs arrays of strings, it is recommended to use arrays of
       `dtype` `~numpy.object_`, `~numpy.bytes_` or `~numpy.str_`, and use
       the free functions in the `numpy.char` module for fast vectorized
       string operations.

    Versus a NumPy array of dtype `~numpy.bytes_` or `~numpy.str_`, this
    class adds the following functionality:

    1) values automatically have whitespace removed from the end
       when indexed

    2) comparison operators automatically remove whitespace from the
       end when comparing values

    3) vectorized string operations are provided as methods
       (e.g. `.endswith`) and infix operators (e.g. ``"+", "*", "%"``)

    chararrays should be created using `numpy.char.array` or
    `numpy.char.asarray`, rather than this constructor directly.

    This constructor creates the array, using `buffer` (with `offset`
    and `strides`) if it is not ``None``. If `buffer` is ``None``, then
    constructs a new array with `strides` in "C order", unless both
    ``len(shape) >= 2`` and ``order='F'``, in which case `strides`
    is in "Fortran order".

    Methods
    -------
    astype
    argsort
    copy
    count
    decode
    dump
    dumps
    encode
    endswith
    expandtabs
    fill
    find
    flatten
    getfield
    index
    isalnum
    isalpha
    isdecimal
    isdigit
    islower
    isnumeric
    isspace
    istitle
    isupper
    item
    join
    ljust
    lower
    lstrip
    nonzero
    put
    ravel
    repeat
    replace
    reshape
    resize
    rfind
    rindex
    rjust
    rsplit
    rstrip
    searchsorted
    setfield
    setflags
    sort
    split
    splitlines
    squeeze
    startswith
    strip
    swapaxes
    swapcase
    take
    title
    tofile
    tolist
    tostring
    translate
    transpose
    upper
    view
    zfill

    Parameters
    ----------
    shape : tuple
        Shape of the array.
    itemsize : int, optional
        Length of each array element, in number of characters. Default is 1.
    unicode : bool, optional
        Are the array elements of type unicode (True) or string (False).
        Default is False.
    buffer : object exposing the buffer interface or str, optional
        Memory address of the start of the array data.  Default is None,
        in which case a new array is created.
    offset : int, optional
        Fixed stride displacement from the beginning of an axis?
        Default is 0. Needs to be >=0.
    """
    strides : array_like of ints, optional
        Strides for the array (see `~numpy.ndarray.strides` for
        full description). Default is None.
    order : {'C', 'F'}, optional
        The order in which the array data is stored in memory: 'C' ->
        "row major" order (the default), 'F' -> "column major"
        (Fortran) order.

    Examples
    --------
    >>> charar = np.char.chararray((3, 3))
    >>> charar[:] = 'a'
    >>> charar
    chararray([[b'a', b'a', b'a'],
               [b'a', b'a', b'a'],
               [b'a', b'a', b'a']], dtype='|S1')

    >>> charar = np.char.chararray(charar.shape, itemsize=5)
    >>> charar[:] = 'abc'
    >>> charar
    chararray([[b'abc', b'abc', b'abc'],
               [b'abc', b'abc', b'abc'],
               [b'abc', b'abc', b'abc']], dtype='|S5')

    """
    # 定义一个新的特殊数组类型 chararray,继承自 ndarray
    def __new__(subtype, shape, itemsize=1, unicode=False, buffer=None,
                offset=0, strides=None, order='C'):
        # 如果 unicode 为 True,则数据类型为 str_,否则为 bytes_
        if unicode:
            dtype = str_
        else:
            dtype = bytes_

        # 将 itemsize 强制转换为 Python 的整数类型,因为使用 NumPy 整数类型会导致 itemsize.itemsize 作为新数组中字符串的大小。
        itemsize = int(itemsize)

        if isinstance(buffer, str):
            # Unicode 对象没有缓冲区接口
            filler = buffer
            buffer = None
        else:
            filler = None

        if buffer is None:
            # 创建一个新的 ndarray 对象,使用指定的形状、数据类型和存储顺序(默认 'C')
            self = ndarray.__new__(subtype, shape, (dtype, itemsize),
                                   order=order)
        else:
            # 创建一个新的 ndarray 对象,使用指定的形状、数据类型、缓冲区、偏移量、步幅和存储顺序
            self = ndarray.__new__(subtype, shape, (dtype, itemsize),
                                   buffer=buffer,
                                   offset=offset, strides=strides,
                                   order=order)
        if filler is not None:
            # 将数组的所有元素填充为指定的 filler 值
            self[...] = filler

        return self

    # 当调用 ufunc(和其他一些函数)时,如果输出是类似字符串的数组,则返回 chararray;否则返回 ndarray
    def __array_wrap__(self, arr, context=None, return_scalar=False):
        if arr.dtype.char in "SUbc":
            return arr.view(type(self))
        return arr

    # 在初始化时,检查数据类型是否为 'VSUbc',否则抛出 ValueError 异常
    def __array_finalize__(self, obj):
        if self.dtype.char not in 'VSUbc':
            raise ValueError("Can only create a chararray from string data.")

    # 获取数组的元素,如果是字符类型,则去除右侧的空格并返回;否则返回原始值
    def __getitem__(self, obj):
        val = ndarray.__getitem__(self, obj)
        if isinstance(val, character):
            return val.rstrip()
        return val

    # 实现说明:这个类的大多数方法都是直接委托给本模块中的自由函数。
    # 然而,那些返回字符串数组的方法应该返回 chararray,因此需要额外的包装。
    def __eq__(self, other):
        """
        Return (self == other) element-wise.

        See Also
        --------
        equal
        """
        return equal(self, other)

    def __ne__(self, other):
        """
        Return (self != other) element-wise.

        See Also
        --------
        not_equal
        """
        return not_equal(self, other)

    def __ge__(self, other):
        """
        Return (self >= other) element-wise.

        See Also
        --------
        greater_equal
        """
        return greater_equal(self, other)

    def __le__(self, other):
        """
        Return (self <= other) element-wise.

        See Also
        --------
        less_equal
        """
        return less_equal(self, other)

    def __gt__(self, other):
        """
        Return (self > other) element-wise.

        See Also
        --------
        greater
        """
        return greater(self, other)

    def __lt__(self, other):
        """
        Return (self < other) element-wise.

        See Also
        --------
        less
        """
        return less(self, other)

    def __add__(self, other):
        """
        Return (self + other), that is string concatenation,
        element-wise for a pair of array_likes of str or unicode.

        See Also
        --------
        add
        """
        return add(self, other)

    def __radd__(self, other):
        """
        Return (other + self), that is string concatenation,
        element-wise for a pair of array_likes of `bytes_` or `str_`.

        See Also
        --------
        add
        """
        return add(other, self)

    def __mul__(self, i):
        """
        Return (self * i), that is string multiple concatenation,
        element-wise.

        See Also
        --------
        multiply
        """
        return asarray(multiply(self, i))

    def __rmul__(self, i):
        """
        Return (self * i), that is string multiple concatenation,
        element-wise.

        See Also
        --------
        multiply
        """
        return asarray(multiply(self, i))

    def __mod__(self, i):
        """
        Return (self % i), that is pre-Python 2.6 string formatting
        (interpolation), element-wise for a pair of array_likes of `bytes_`
        or `str_`.

        See Also
        --------
        mod
        """
        return asarray(mod(self, i))

    def __rmod__(self, other):
        """
        Not implemented for the right-hand operand.

        See Also
        --------
        NotImplemented
        """
        return NotImplemented
    def argsort(self, axis=-1, kind=None, order=None):
        """
        Return the indices that sort the array lexicographically.

        For full documentation see `numpy.argsort`, for which this method is
        in fact merely a "thin wrapper."

        Examples
        --------
        >>> c = np.array(['a1b c', '1b ca', 'b ca1', 'Ca1b'], 'S5')
        >>> c = c.view(np.char.chararray); c
        chararray(['a1b c', '1b ca', 'b ca1', 'Ca1b'],
              dtype='|S5')
        >>> c[c.argsort()]
        chararray(['1b ca', 'Ca1b', 'a1b c', 'b ca1'],
              dtype='|S5')

        """
        # 使用 __array__ 方法将对象转换为 ndarray 后调用其 argsort 方法
        return self.__array__().argsort(axis, kind, order)
    argsort.__doc__ = ndarray.argsort.__doc__

    def capitalize(self):
        """
        Return a copy of `self` with only the first character of each element
        capitalized.

        See Also
        --------
        char.capitalize

        """
        # 调用 numpy.char.capitalize 函数,将每个元素的首字母大写
        return asarray(capitalize(self))

    def center(self, width, fillchar=' '):
        """
        Return a copy of `self` with its elements centered in a
        string of length `width`.

        See Also
        --------
        center
        """
        # 调用 numpy.char.center 函数,将每个元素居中在长度为 width 的字符串中
        return asarray(center(self, width, fillchar))

    def count(self, sub, start=0, end=None):
        """
        Returns an array with the number of non-overlapping occurrences of
        substring `sub` in the range [`start`, `end`].

        See Also
        --------
        char.count

        """
        # 调用 numpy.char.count 函数,统计每个元素中子字符串 sub 的出现次数
        return count(self, sub, start, end)

    def decode(self, encoding=None, errors=None):
        """
        Calls ``bytes.decode`` element-wise.

        See Also
        --------
        char.decode

        """
        # 调用 numpy.char.decode 函数,对每个元素进行 bytes 解码
        return decode(self, encoding, errors)

    def encode(self, encoding=None, errors=None):
        """
        Calls :meth:`str.encode` element-wise.

        See Also
        --------
        char.encode

        """
        # 调用 numpy.char.encode 函数,对每个元素进行字符串编码
        return encode(self, encoding, errors)

    def endswith(self, suffix, start=0, end=None):
        """
        Returns a boolean array which is `True` where the string element
        in `self` ends with `suffix`, otherwise `False`.

        See Also
        --------
        char.endswith

        """
        # 调用 numpy.char.endswith 函数,判断每个元素是否以 suffix 结尾
        return endswith(self, suffix, start, end)

    def expandtabs(self, tabsize=8):
        """
        Return a copy of each string element where all tab characters are
        replaced by one or more spaces.

        See Also
        --------
        char.expandtabs

        """
        # 调用 numpy.char.expandtabs 函数,将每个元素中的制表符替换为空格
        return asarray(expandtabs(self, tabsize))

    def find(self, sub, start=0, end=None):
        """
        For each element, return the lowest index in the string where
        substring `sub` is found.

        See Also
        --------
        char.find

        """
        # 调用 numpy.char.find 函数,返回每个元素中子字符串 sub 的最低索引位置
        return find(self, sub, start, end)
    def index(self, sub, start=0, end=None):
        """
        在字符串中查找子字符串 `sub`,如果找到则返回第一次出现的位置索引;如果未找到,抛出 `ValueError` 异常。

        See Also
        --------
        char.index
        """
        return index(self, sub, start, end)

    def isalnum(self):
        """
        如果字符串中的所有字符都是字母数字并且至少有一个字符,则返回 True;否则返回 False。

        See Also
        --------
        char.isalnum
        """
        return isalnum(self)

    def isalpha(self):
        """
        如果字符串中的所有字符都是字母并且至少有一个字符,则返回 True;否则返回 False。

        See Also
        --------
        char.isalpha
        """
        return isalpha(self)

    def isdigit(self):
        """
        如果字符串中的所有字符都是数字并且至少有一个字符,则返回 True;否则返回 False。

        See Also
        --------
        char.isdigit
        """
        return isdigit(self)

    def islower(self):
        """
        如果字符串中所有大小写字符都是小写并且至少有一个大小写字符,则返回 True;否则返回 False。

        See Also
        --------
        char.islower
        """
        return islower(self)

    def isspace(self):
        """
        如果字符串中只包含空白字符并且至少有一个字符,则返回 True;否则返回 False。

        See Also
        --------
        char.isspace
        """
        return isspace(self)

    def istitle(self):
        """
        如果字符串是标题格式(即每个单词首字母大写)并且至少有一个字符,则返回 True;否则返回 False。

        See Also
        --------
        char.istitle
        """
        return istitle(self)

    def isupper(self):
        """
        如果字符串中所有大小写字符都是大写并且至少有一个大小写字符,则返回 True;否则返回 False。

        See Also
        --------
        char.isupper
        """
        return isupper(self)

    def join(self, seq):
        """
        将序列 `seq` 中的字符串连接成一个字符串并返回。

        See Also
        --------
        char.join
        """
        return join(self, seq)

    def ljust(self, width, fillchar=' '):
        """
        返回一个数组,其中 `self` 中的元素左对齐在长度为 `width` 的字符串中。

        See Also
        --------
        char.ljust
        """
        return asarray(ljust(self, width, fillchar))
    def lower(self):
        """
        Return an array with the elements of `self` converted to
        lowercase.

        See Also
        --------
        char.lower
        """
        # 将 `self` 中的每个元素转换为小写,并返回转换后的数组
        return asarray(lower(self))

    def lstrip(self, chars=None):
        """
        For each element in `self`, return a copy with the leading characters
        removed.

        See Also
        --------
        char.lstrip
        """
        # 对 `self` 中的每个元素进行去除开头指定字符后返回副本的操作
        return lstrip(self, chars)

    def partition(self, sep):
        """
        Partition each element in `self` around `sep`.

        See Also
        --------
        partition
        """
        # 对 `self` 中的每个元素使用 `sep` 进行分割,并返回分割后的数组
        return asarray(partition(self, sep))

    def replace(self, old, new, count=None):
        """
        For each element in `self`, return a copy of the string with all
        occurrences of substring `old` replaced by `new`.

        See Also
        --------
        char.replace
        """
        # 对 `self` 中的每个元素进行字符串替换操作,返回替换后的副本
        return replace(self, old, new, count if count is not None else -1)

    def rfind(self, sub, start=0, end=None):
        """
        For each element in `self`, return the highest index in the string
        where substring `sub` is found, such that `sub` is contained
        within [`start`, `end`].

        See Also
        --------
        char.rfind
        """
        # 返回 `self` 中每个元素中指定子串 `sub` 的最高索引,范围为 [`start`, `end`]
        return rfind(self, sub, start, end)

    def rindex(self, sub, start=0, end=None):
        """
        Like `rfind`, but raises :exc:`ValueError` when the substring `sub` is
        not found.

        See Also
        --------
        char.rindex
        """
        # 类似 `rfind`,但是当子串 `sub` 未找到时会引发 :exc:`ValueError`
        return rindex(self, sub, start, end)

    def rjust(self, width, fillchar=' '):
        """
        Return an array with the elements of `self`
        right-justified in a string of length `width`.

        See Also
        --------
        char.rjust
        """
        # 返回 `self` 中的每个元素右对齐到指定 `width` 的字符串中,并返回数组
        return asarray(rjust(self, width, fillchar))

    def rpartition(self, sep):
        """
        Partition each element in `self` around `sep`.

        See Also
        --------
        rpartition
        """
        # 对 `self` 中的每个元素使用 `sep` 进行分割,并返回分割后的数组
        return asarray(rpartition(self, sep))

    def rsplit(self, sep=None, maxsplit=None):
        """
        For each element in `self`, return a list of the words in
        the string, using `sep` as the delimiter string.

        See Also
        --------
        char.rsplit
        """
        # 对 `self` 中的每个元素按照 `sep` 分割字符串,并返回单词列表
        return rsplit(self, sep, maxsplit)

    def rstrip(self, chars=None):
        """
        For each element in `self`, return a copy with the trailing
        characters removed.

        See Also
        --------
        char.rstrip
        """
        # 对 `self` 中的每个元素进行去除结尾指定字符后返回副本的操作
        return rstrip(self, chars)

    def split(self, sep=None, maxsplit=None):
        """
        For each element in `self`, return a list of the words in the
        string, using `sep` as the delimiter string.

        See Also
        --------
        char.split
        """
        # 对 `self` 中的每个元素按照 `sep` 分割字符串,并返回单词列表
        return split(self, sep, maxsplit)
    def splitlines(self, keepends=None):
        """
        对于 `self` 中的每个元素,返回一个列表,其中包含元素的行,以行界限分割。

        See Also
        --------
        char.splitlines

        """
        return splitlines(self, keepends)

    def startswith(self, prefix, start=0, end=None):
        """
        返回一个布尔数组,其中 `self` 中的字符串元素在 `prefix` 开头时为 `True`,否则为 `False`。

        See Also
        --------
        char.startswith

        """
        return startswith(self, prefix, start, end)

    def strip(self, chars=None):
        """
        对于 `self` 中的每个元素,返回一个副本,其中移除了前导和尾随的字符。

        See Also
        --------
        char.strip

        """
        return strip(self, chars)

    def swapcase(self):
        """
        对于 `self` 中的每个元素,返回一个字符串副本,其中大写字符转换为小写,小写字符转换为大写。

        See Also
        --------
        char.swapcase

        """
        return asarray(swapcase(self))

    def title(self):
        """
        对于 `self` 中的每个元素,返回一个首字母大写的版本:单词以大写字母开头,其余的字母都小写。

        See Also
        --------
        char.title

        """
        return asarray(title(self))

    def translate(self, table, deletechars=None):
        """
        对于 `self` 中的每个元素,返回一个字符串副本,其中删除了在可选参数 `deletechars` 中出现的所有字符,
        并且剩余的字符通过给定的转换表进行映射。

        See Also
        --------
        char.translate

        """
        return asarray(translate(self, table, deletechars))

    def upper(self):
        """
        返回一个将 `self` 中的元素转换为大写的数组。

        See Also
        --------
        char.upper

        """
        return asarray(upper(self))

    def zfill(self, width):
        """
        返回一个数值字符串,左侧填充零,长度为 `width`。

        See Also
        --------
        char.zfill

        """
        return asarray(zfill(self, width))

    def isnumeric(self):
        """
        对于 `self` 中的每个元素,如果元素仅包含数字字符,则返回 `True`。

        See Also
        --------
        char.isnumeric

        """
        return isnumeric(self)

    def isdecimal(self):
        """
        对于 `self` 中的每个元素,如果元素仅包含十进制数字字符,则返回 `True`。

        See Also
        --------
        char.isdecimal

        """
        return isdecimal(self)
# 设置模块名称为 "numpy.char"
@set_module("numpy.char")
def array(obj, itemsize=None, copy=True, unicode=None, order=None):
    """
    创建一个 `~numpy.char.chararray`。

    .. note::
       该类用于向后兼容 numarray。
       新代码(不考虑 numarray 兼容性)应该使用 `bytes_` 或 `str_` 类型的数组,
       并使用 :mod:`numpy.char` 中的自由函数进行快速向量化的字符串操作。

    与 dtype 为 `bytes_` 或 `str_` 的 NumPy 数组相比,这个类增加了以下功能:

    1) 在索引时自动去除值末尾的空白字符

    2) 在比较值时,比较运算符会自动去除末尾的空白字符

    3) 提供作为方法的向量化字符串操作(例如 `chararray.endswith <numpy.char.chararray.endswith>`)
       和中缀操作符(例如 ``+, *, %``)

    Parameters
    ----------
    obj : str 或类似 unicode 的数组

    itemsize : int, optional
        `itemsize` 是结果数组中每个标量的字符数。如果 `itemsize` 为 None,
        并且 `obj` 是对象数组或 Python 列表,则 `itemsize` 将自动确定。
        如果提供了 `itemsize` 并且 `obj` 的类型是 str 或 unicode,则 `obj` 字符串将被分块为 `itemsize` 长度的片段。

    copy : bool, optional
        如果为 True(默认),则复制对象。否则,只有当 ``__array__`` 返回复制时,
        如果 obj 是嵌套序列或需要满足其他任何要求(`itemsize`、unicode、`order` 等)时才会进行复制。

    unicode : bool, optional
        当为 True 时,生成的 `~numpy.char.chararray` 可以包含 Unicode 字符;
        当为 False 时,只能包含 8 位字符。如果 unicode 为 None,并且 `obj` 是以下之一:

        - `~numpy.char.chararray`,
        - 类型为 :class:`str_` 或 :class:`bytes_` 的 ndarray
        - Python 的 :class:`str` 或 :class:`bytes` 对象,

        那么输出数组的 Unicode 设置将自动确定。

    order : {'C', 'F', 'A'}, optional
        指定数组的顺序。如果 order 为 'C'(默认),则数组将按 C 连续顺序排列(最后一个索引变化最快)。
        如果 order 为 'F',则返回的数组将按 Fortran 连续顺序排列(第一个索引变化最快)。
        如果 order 为 'A',则返回的数组可以是任何顺序(C 连续、Fortran 连续或甚至是不连续的)。
    """
    # 检查对象是否为 bytes 或者 str 类型
    if isinstance(obj, (bytes, str)):
        # 如果未提供 unicode 参数,则根据 obj 类型设定 unicode 变量
        if unicode is None:
            if isinstance(obj, str):
                unicode = True
            else:
                unicode = False

        # 如果未提供 itemsize 参数,则设定为 obj 的长度
        if itemsize is None:
            itemsize = len(obj)
        
        # 计算数组的形状,假设每个元素长度为 itemsize
        shape = len(obj) // itemsize
        
        # 创建一个 chararray 对象,使用给定的参数
        return chararray(shape, itemsize=itemsize, unicode=unicode,
                         buffer=obj, order=order)

    # 如果对象是 list 或 tuple 类型,则将其转换为 ndarray
    if isinstance(obj, (list, tuple)):
        obj = asarray(obj)

    # 如果对象是 ndarray 并且其元素类型是 character 的子类
    if isinstance(obj, ndarray) and issubclass(obj.dtype.type, character):
        # 如果 obj 不是 chararray 类型,则将其视图转换为 chararray
        if not isinstance(obj, chararray):
            obj = obj.view(chararray)

        # 如果未提供 itemsize 参数,则根据 obj 的 itemsize 设定
        if itemsize is None:
            itemsize = obj.itemsize
            # 对于 Unicode,需要将 itemsize 除以单个 Unicode 字符的大小(NumPy 默认为 4)
            if issubclass(obj.dtype.type, str_):
                itemsize //= 4

        # 如果未提供 unicode 参数,则根据 obj 的 dtype 设定
        if unicode is None:
            if issubclass(obj.dtype.type, str_):
                unicode = True
            else:
                unicode = False

        # 根据 unicode 参数设定 dtype 类型
        if unicode:
            dtype = str_
        else:
            dtype = bytes_

        # 如果提供了 order 参数,则使用 asnarray 函数重新生成数组
        if order is not None:
            obj = asarray(obj, order=order)

        # 如果需要复制,或者 itemsize 不等于 obj 的 itemsize,或者类型不匹配,则进行数据类型转换
        if (copy or
                (itemsize != obj.itemsize) or
                (not unicode and isinstance(obj, str_)) or
                (unicode and isinstance(obj, bytes_))):
            obj = obj.astype((dtype, int(itemsize)))

        return obj

    # 如果对象是 ndarray 并且其元素类型是 object 的子类
    if isinstance(obj, ndarray) and issubclass(obj.dtype.type, object):
        # 如果未提供 itemsize 参数,则将输入数组转换为列表,以便 ndarray 构造函数自动确定 itemsize
        if itemsize is None:
            obj = obj.tolist()
            # 继续默认情况处理

    # 根据 unicode 参数设定 dtype 类型
    if unicode:
        dtype = str_
    else:
        dtype = bytes_

    # 如果未提供 itemsize 参数,则使用 narray 函数生成数组
    if itemsize is None:
        val = array(obj, dtype=dtype, order=order, subok=True)
    else:
        val = array(obj, dtype=(dtype, itemsize), order=order, subok=True)

    # 返回 val 视图,类型为 chararray
    return val.view(chararray)
# 将输入对象转换为 `~numpy.char.chararray`,仅在必要时复制数据。
@set_module("numpy.char")
def asarray(obj, itemsize=None, unicode=None, order=None):
    """
    Convert the input to a `~numpy.char.chararray`, copying the data only if
    necessary.

    Versus a NumPy array of dtype `bytes_` or `str_`, this
    class adds the following functionality:

    1) values automatically have whitespace removed from the end
       when indexed

    2) comparison operators automatically remove whitespace from the
       end when comparing values

    3) vectorized string operations are provided as methods
       (e.g. `chararray.endswith <numpy.char.chararray.endswith>`)
       and infix operators (e.g. ``+``, ``*``, ``%``)

    Parameters
    ----------
    obj : array of str or unicode-like
        输入的字符串数组或类似 unicode 的对象

    itemsize : int, optional
        `itemsize` 是结果数组中每个标量的字符数。如果 `itemsize` 为 None,并且 `obj` 是对象数组或 Python 列表,
        `itemsize` 将自动确定。如果提供了 `itemsize` 并且 `obj` 的类型为 str 或 unicode,则 `obj` 字符串将被分成 `itemsize` 段。

    unicode : bool, optional
        当为 True 时,生成的 `~numpy.char.chararray` 可包含 Unicode 字符;当为 False 时,仅包含 8 位字符。
        如果 unicode 为 None,并且 `obj` 是以下类型之一:

        - `~numpy.char.chararray`
        - 类型为 `str_` 或 `unicode_` 的 ndarray
        - Python 的 str 或 unicode 对象

        输出数组的 Unicode 设置将自动确定。

    order : {'C', 'F'}, optional
        指定数组的顺序。如果 order 为 'C'(默认),则数组将以 C 连续顺序存储(最后一个索引变化最快)。
        如果 order 为 'F',则返回的数组将以 Fortran 连续顺序存储(第一个索引变化最快)。

    Examples
    --------
    >>> np.char.asarray(['hello', 'world'])
    chararray(['hello', 'world'], dtype='<U5')
    
    """
    # 调用 numpy 的 array 函数,返回相应的 chararray 对象
    return array(obj, itemsize, copy=False,
                 unicode=unicode, order=order)

.\numpy\numpy\_core\defchararray.pyi

# 引入必要的类型提示和函数重载支持
from typing import (
    Literal as L,               # 别名 L 表示 Literal
    overload,                   # 装饰器 overload 支持函数重载
    TypeVar,                    # 泛型变量 TypeVar
    Any,                        # 表示任意类型的 Any
    SupportsIndex,              # 表示支持索引的类型
    SupportsInt,                # 表示支持整数的类型
)

import numpy as np               # 导入 NumPy 库
from numpy import (              # 从 NumPy 中导入以下标识符
    ndarray,                     # 多维数组类型 ndarray
    dtype,                       # 数据类型 dtype
    str_ as _StrDType,           # 字符串类型 str_ 别名为 _StrDType
    bytes_ as _BytesDType,       # 字节类型 bytes_ 别名为 _BytesDType
    int_ as _IntDType,           # 整数类型 int_ 别名为 _IntDType
    object_ as _ObjectDType,     # 对象类型 object_ 别名为 _ObjectDType
    _OrderKACF,                  # 私有类型 _OrderKACF
    _ShapeType,                  # 私有类型 _ShapeType
    _CharDType,                  # 私有类型 _CharDType
    _SupportsBuffer,             # 私有类型 _SupportsBuffer
)

from numpy._typing import (       # 从 NumPy 的类型定义中导入以下标识符
    NDArray,                      # 泛型数组类型 NDArray
    _ShapeLike,                   # 形状类型 _ShapeLike
    _ArrayLikeStr_co as U_co,     # 可变字符串数组类型别名 U_co
    _ArrayLikeBytes_co as S_co,   # 可变字节字符串数组类型别名 S_co
    _ArrayLikeInt_co as i_co,     # 可变整数数组类型别名 i_co
    _ArrayLikeBool_co as b_co,    # 可变布尔数组类型别名 b_co
)

from numpy._core.multiarray import compare_chararrays as compare_chararrays  # 导入字符数组比较函数

_SCT = TypeVar("_SCT", str_, bytes_)      # 定义 _SCT 泛型变量,可以是 str 或 bytes 类型
_CharArray = chararray[Any, dtype[_SCT]]  # 定义 _CharArray 类型为 chararray 类的泛型实例

# chararray 类的定义,继承自 ndarray,支持字符数据类型 _CharDType
class chararray(ndarray[_ShapeType, _CharDType]):
    
    @overload
    def __new__(
        subtype,
        shape: _ShapeLike,                 # 形状参数,类型为 _ShapeLike
        itemsize: SupportsIndex | SupportsInt = ...,  # 元素大小,支持索引或整数
        unicode: L[False] = ...,           # 是否是 Unicode 类型的标志,False 表示不是
        buffer: _SupportsBuffer = ...,     # 缓冲区对象,支持 _SupportsBuffer
        offset: SupportsIndex = ...,       # 偏移量,支持索引
        strides: _ShapeLike = ...,         # 步幅,类型为 _ShapeLike
        order: _OrderKACF = ...,          # 排序顺序,类型为 _OrderKACF
    ) -> chararray[Any, dtype[bytes_]]: ...  # 返回 chararray 类型的实例,字符数据类型为 bytes_

    @overload
    def __new__(
        subtype,
        shape: _ShapeLike,
        itemsize: SupportsIndex | SupportsInt = ...,
        unicode: L[True] = ...,            # 是否是 Unicode 类型的标志,True 表示是
        buffer: _SupportsBuffer = ...,
        offset: SupportsIndex = ...,
        strides: _ShapeLike = ...,
        order: _OrderKACF = ...,
    ) -> chararray[Any, dtype[str_]]: ...  # 返回 chararray 类型的实例,字符数据类型为 str_

    def __array_finalize__(self, obj: object) -> None: ...  # 数组初始化之后的清理方法,无返回值
    def __mul__(self, other: i_co) -> chararray[Any, _CharDType]: ...  # 乘法操作,返回 chararray 类型的实例
    def __rmul__(self, other: i_co) -> chararray[Any, _CharDType]: ...  # 右乘法操作,返回 chararray 类型的实例
    def __mod__(self, i: Any) -> chararray[Any, _CharDType]: ...  # 取模操作,返回 chararray 类型的实例

    @overload
    def __eq__(
        self: _CharArray[str_],   # 字符数组类型为 str_
        other: U_co,              # 另一数组的类型为 U_co
    ) -> NDArray[np.bool]: ...    # 返回布尔数组 NDArray[np.bool]

    @overload
    def __eq__(
        self: _CharArray[bytes_],  # 字符数组类型为 bytes_
        other: S_co,               # 另一数组的类型为 S_co
    ) -> NDArray[np.bool]: ...     # 返回布尔数组 NDArray[np.bool]

    @overload
    def __ne__(
        self: _CharArray[str_],   # 字符数组类型为 str_
        other: U_co,              # 另一数组的类型为 U_co
    ) -> NDArray[np.bool]: ...    # 返回布尔数组 NDArray[np.bool]

    @overload
    def __ne__(
        self: _CharArray[bytes_],  # 字符数组类型为 bytes_
        other: S_co,               # 另一数组的类型为 S_co
    ) -> NDArray[np.bool]: ...     # 返回布尔数组 NDArray[np.bool]

    @overload
    def __ge__(
        self: _CharArray[str_],   # 字符数组类型为 str_
        other: U_co,              # 另一数组的类型为 U_co
    ) -> NDArray[np.bool]: ...    # 返回布尔数组 NDArray[np.bool]

    @overload
    def __ge__(
        self: _CharArray[bytes_],  # 字符数组类型为 bytes_
        other: S_co,               # 另一数组的类型为 S_co
    ) -> NDArray[np.bool]: ...     # 返回布尔数组 NDArray[np.bool]

    @overload
    def __le__(
        self: _CharArray[str_],   # 字符数组类型为 str_
        other: U_co,              # 另一数组的类型为 U_co
    ) -> NDArray[np.bool]: ...    # 返回布尔数组 NDArray[np.bool]

    @overload
    def __le__(
        self: _CharArray[bytes_],  # 字符数组类型为 bytes_
        other: S_co,               # 另一数组的类型为 S_co
    ) -> NDArray[np.bool]: ...     # 返回布尔数组 NDArray[np.bool]

    @overload
    def __gt__(
        self: _CharArray[str_],   # 字符数组类型为 str_
        other: U_co,              # 另一数组的类型为 U_co
    ) -> NDArray[np.bool]: ...    # 返回布尔数组 NDArray[np.bool]

    @overload
    def __gt__(
        self: _CharArray[bytes_],  # 字符数组类型为 bytes_
        other: S_co,               # 另一数组的类型为 S_co
    ) -> NDArray[np.bool]: ...     # 返回布尔数组 NDArray[np.bool]

    @overload
    def __lt__(
        self: _CharArray[str_],   # 字符数组类型为 str_
        other: U_co,              # 另一数组的类型为 U_co
    ) -> NDArray[np.bool]: ...    # 返回布尔数组 NDArray[np.bool]
    def __lt__(
        self: _CharArray[bytes_],
        other: S_co,
    ) -> NDArray[np.bool]:
    # 定义小于比较方法,返回一个布尔类型的 NumPy 数组
    ...

    @overload
    def __add__(
        self: _CharArray[str_],
        other: U_co,
    ) -> _CharArray[str_]:
    # 定义字符串数组与其他类型相加的重载方法,返回字符串数组
    @overload
    def __add__(
        self: _CharArray[bytes_],
        other: S_co,
    ) -> _CharArray[bytes_]:
    # 定义字节串数组与其他类型相加的重载方法,返回字节串数组
    ...

    @overload
    def __radd__(
        self: _CharArray[str_],
        other: U_co,
    ) -> _CharArray[str_]:
    # 定义其他类型与字符串数组相加的反向重载方法,返回字符串数组
    @overload
    def __radd__(
        self: _CharArray[bytes_],
        other: S_co,
    ) -> _CharArray[bytes_]:
    # 定义其他类型与字节串数组相加的反向重载方法,返回字节串数组
    ...

    @overload
    def center(
        self: _CharArray[str_],
        width: i_co,
        fillchar: U_co = ...,
    ) -> _CharArray[str_]:
    # 定义字符串数组的居中方法,返回字符串数组
    @overload
    def center(
        self: _CharArray[bytes_],
        width: i_co,
        fillchar: S_co = ...,
    ) -> _CharArray[bytes_]:
    # 定义字节串数组的居中方法,返回字节串数组
    ...

    @overload
    def count(
        self: _CharArray[str_],
        sub: U_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]:
    # 定义字符串数组的计数方法,返回整型的 NumPy 数组
    @overload
    def count(
        self: _CharArray[bytes_],
        sub: S_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]:
    # 定义字节串数组的计数方法,返回整型的 NumPy 数组
    ...

    def decode(
        self: _CharArray[bytes_],
        encoding: None | str = ...,
        errors: None | str = ...,
    ) -> _CharArray[str_]:
    # 定义字节串数组的解码方法,返回字符串数组
    ...

    def encode(
        self: _CharArray[str_],
        encoding: None | str = ...,
        errors: None | str = ...,
    ) -> _CharArray[bytes_]:
    # 定义字符串数组的编码方法,返回字节串数组
    ...

    @overload
    def endswith(
        self: _CharArray[str_],
        suffix: U_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[np.bool]:
    # 定义字符串数组的后缀判断方法,返回布尔类型的 NumPy 数组
    @overload
    def endswith(
        self: _CharArray[bytes_],
        suffix: S_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[np.bool]:
    # 定义字节串数组的后缀判断方法,返回布尔类型的 NumPy 数组
    ...

    def expandtabs(
        self,
        tabsize: i_co = ...,
    ) -> chararray[Any, _CharDType]:
    # 定义替换制表符为多个空格的方法,返回字符数组
    ...

    @overload
    def find(
        self: _CharArray[str_],
        sub: U_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]:
    # 定义字符串数组的查找方法,返回整型的 NumPy 数组
    @overload
    def find(
        self: _CharArray[bytes_],
        sub: S_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]:
    # 定义字节串数组的查找方法,返回整型的 NumPy 数组
    ...

    @overload
    def index(
        self: _CharArray[str_],
        sub: U_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]:
    # 定义字符串数组的索引方法,返回整型的 NumPy 数组
    @overload
    def index(
        self: _CharArray[bytes_],
        sub: S_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]:
    # 定义字节串数组的索引方法,返回整型的 NumPy 数组
    ...

    @overload
    def join(
        self: _CharArray[str_],
        seq: U_co,
    ) -> _CharArray[str_]:
    # 定义字符串数组的连接方法,返回字符串数组
    @overload
    def join(
        self: _CharArray[bytes_],
        seq: S_co,
    ) -> _CharArray[bytes_]:
    # 定义字节串数组的连接方法,返回字节串数组
    ...

    @overload
    def ljust(
        self: _CharArray[str_],
        width: i_co,
        fillchar: U_co = ...,

        width: i_co,
        fillchar: U_co = ...,
    ) -> _CharArray[str_]:
    # 定义字符串数组的左对齐方法,返回字符串数组
    @overload
    def ljust(
        self: _CharArray[bytes_],
        width: i_co,
        fillchar: S_co = ...,
    ) -> _CharArray[bytes_]:
    # 定义字节串数组的左对齐方法,返回字节串数组
    ...
    ) -> _CharArray[str_]: ...
    # 定义 ljust 方法的类型注解和返回类型为字符数组(字符串)的泛型
    @overload
    def ljust(
        self: _CharArray[bytes_],
        width: i_co,
        fillchar: S_co = ...,
    ) -> _CharArray[bytes_]: ...
    # ljust 方法的重载定义,接受一个整数宽度和一个填充字符(字节序列),返回类型为字节序列的字符数组

    @overload
    def lstrip(
        self: _CharArray[str_],
        chars: None | U_co = ...,
    ) -> _CharArray[str_]: ...
    @overload
    def lstrip(
        self: _CharArray[bytes_],
        chars: None | S_co = ...,
    ) -> _CharArray[bytes_]: ...
    # lstrip 方法的重载定义,接受一个可选的字符集参数,返回类型根据输入的字符数组类型而定

    @overload
    def partition(
        self: _CharArray[str_],
        sep: U_co,
    ) -> _CharArray[str_]: ...
    @overload
    def partition(
        self: _CharArray[bytes_],
        sep: S_co,
    ) -> _CharArray[bytes_]: ...
    # partition 方法的重载定义,接受一个分隔符参数,返回类型根据输入的字符数组类型而定

    @overload
    def replace(
        self: _CharArray[str_],
        old: U_co,
        new: U_co,
        count: None | i_co = ...,
    ) -> _CharArray[str_]: ...
    @overload
    def replace(
        self: _CharArray[bytes_],
        old: S_co,
        new: S_co,
        count: None | i_co = ...,
    ) -> _CharArray[bytes_]: ...
    # replace 方法的重载定义,接受一个旧值、一个新值和一个可选的计数参数,返回类型根据输入的字符数组类型而定

    @overload
    def rfind(
        self: _CharArray[str_],
        sub: U_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]: ...
    @overload
    def rfind(
        self: _CharArray[bytes_],
        sub: S_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]: ...
    # rfind 方法的重载定义,接受一个子字符串、可选的起始位置和结束位置参数,返回类型为整数数组(numpy 数组)

    @overload
    def rindex(
        self: _CharArray[str_],
        sub: U_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]: ...
    @overload
    def rindex(
        self: _CharArray[bytes_],
        sub: S_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[int_]: ...
    # rindex 方法的重载定义,接受一个子字符串、可选的起始位置和结束位置参数,返回类型为整数数组(numpy 数组)

    @overload
    def rjust(
        self: _CharArray[str_],
        width: i_co,
        fillchar: U_co = ...,
    ) -> _CharArray[str_]: ...
    @overload
    def rjust(
        self: _CharArray[bytes_],
        width: i_co,
        fillchar: S_co = ...,
    ) -> _CharArray[bytes_]: ...
    # rjust 方法的重载定义,接受一个整数宽度和一个填充字符(字符或字节序列),返回类型根据输入的字符数组类型而定

    @overload
    def rpartition(
        self: _CharArray[str_],
        sep: U_co,
    ) -> _CharArray[str_]: ...
    @overload
    def rpartition(
        self: _CharArray[bytes_],
        sep: S_co,
    ) -> _CharArray[bytes_]: ...
    # rpartition 方法的重载定义,接受一个分隔符参数,返回类型根据输入的字符数组类型而定

    @overload
    def rsplit(
        self: _CharArray[str_],
        sep: None | U_co = ...,
        maxsplit: None | i_co = ...,
    ) -> NDArray[object_]: ...
    @overload
    def rsplit(
        self: _CharArray[bytes_],
        sep: None | S_co = ...,
        maxsplit: None | i_co = ...,
    ) -> NDArray[object_]: ...
    # rsplit 方法的重载定义,接受一个可选的分隔符和最大分割次数参数,返回类型为对象数组(numpy 数组)

    @overload
    def rstrip(
        self: _CharArray[str_],
        chars: None | U_co = ...,
    ) -> _CharArray[str_]: ...
    @overload
    def rstrip(
        self: _CharArray[bytes_],
        chars: None | S_co = ...,
    ) -> _CharArray[bytes_]: ...
    # rstrip 方法的重载定义,接受一个可选的字符集参数,返回类型根据输入的字符数组类型而定

    @overload
    def split(
        self: _CharArray[str_],
        sep: None | U_co = ...,
        maxsplit: None | i_co = ...,
    ) -> NDArray[object_]: ...
    @overload
    # 定义一个方法 `split`,接受一些参数,并返回一个对象数组 NDArray[object_]
    def split(
        self: _CharArray[bytes_],
        sep: None | S_co = ...,
        maxsplit: None | i_co = ...,
    ) -> NDArray[object_]: ...

    # 定义一个方法 `splitlines`,接受一个参数 keepends,并返回一个对象数组 NDArray[object_]
    def splitlines(self, keepends: None | b_co = ...) -> NDArray[object_]: ...

    # 声明一个装饰器函数 `startswith` 的重载,接受不同的参数类型,返回一个布尔类型的数组 NDArray[np.bool]
    @overload
    def startswith(
        self: _CharArray[str_],
        prefix: U_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[np.bool]: ...
    @overload
    def startswith(
        self: _CharArray[bytes_],
        prefix: S_co,
        start: i_co = ...,
        end: None | i_co = ...,
    ) -> NDArray[np.bool]: ...

    # 声明一个装饰器函数 `strip` 的重载,接受不同的参数类型,返回一个 `_CharArray` 类型的对象数组
    @overload
    def strip(
        self: _CharArray[str_],
        chars: None | U_co = ...,
    ) -> _CharArray[str_]: ...
    @overload
    def strip(
        self: _CharArray[bytes_],
        chars: None | S_co = ...,
    ) -> _CharArray[bytes_]: ...

    # 声明一个装饰器函数 `translate` 的重载,接受不同的参数类型,返回一个 `_CharArray` 类型的对象数组
    @overload
    def translate(
        self: _CharArray[str_],
        table: U_co,
        deletechars: None | U_co = ...,
    ) -> _CharArray[str_]: ...
    @overload
    def translate(
        self: _CharArray[bytes_],
        table: S_co,
        deletechars: None | S_co = ...,
    ) -> _CharArray[bytes_]: ...

    # 定义一个方法 `zfill`,接受一个参数 width,返回一个特定形状和字符数据类型的对象数组 chararray[Any, _CharDType]
    def zfill(self, width: _ArrayLikeInt_co) -> chararray[Any, _CharDType]: ...

    # 定义一个方法 `capitalize`,不接受参数,返回一个特定形状和字符数据类型的对象数组 chararray[_ShapeType, _CharDType]
    def capitalize(self) -> chararray[_ShapeType, _CharDType]: ...

    # 定义一个方法 `title`,不接受参数,返回一个特定形状和字符数据类型的对象数组 chararray[_ShapeType, _CharDType]
    def title(self) -> chararray[_ShapeType, _CharDType]: ...

    # 定义一个方法 `swapcase`,不接受参数,返回一个特定形状和字符数据类型的对象数组 chararray[_ShapeType, _CharDType]
    def swapcase(self) -> chararray[_ShapeType, _CharDType]: ...

    # 定义一个方法 `lower`,不接受参数,返回一个特定形状和字符数据类型的对象数组 chararray[_ShapeType, _CharDType]
    def lower(self) -> chararray[_ShapeType, _CharDType]: ...

    # 定义一个方法 `upper`,不接受参数,返回一个特定形状和字符数据类型的对象数组 chararray[_ShapeType, _CharDType]
    def upper(self) -> chararray[_ShapeType, _CharDType]: ...

    # 定义一个方法 `isalnum`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def isalnum(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `isalpha`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def isalpha(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `isdigit`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def isdigit(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `islower`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def islower(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `isspace`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def isspace(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `istitle`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def istitle(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `isupper`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def isupper(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `isnumeric`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def isnumeric(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...

    # 定义一个方法 `isdecimal`,不接受参数,返回一个特定形状和布尔数据类型的数组 ndarray[_ShapeType, dtype[np.bool]]
    def isdecimal(self) -> ndarray[_ShapeType, dtype[np.bool]]: ...
__all__: list[str]
# 定义模块中所有公开的函数和变量名称列表

# Comparison
@overload
def equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
# 函数重载:定义两个版本的equal函数,分别处理不同类型的输入参数,并返回布尔类型的NumPy数组

@overload
def not_equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def not_equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
# 函数重载:定义两个版本的not_equal函数,分别处理不同类型的输入参数,并返回布尔类型的NumPy数组

@overload
def greater_equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def greater_equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
# 函数重载:定义两个版本的greater_equal函数,分别处理不同类型的输入参数,并返回布尔类型的NumPy数组

@overload
def less_equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def less_equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
# 函数重载:定义两个版本的less_equal函数,分别处理不同类型的输入参数,并返回布尔类型的NumPy数组

@overload
def greater(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def greater(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
# 函数重载:定义两个版本的greater函数,分别处理不同类型的输入参数,并返回布尔类型的NumPy数组

@overload
def less(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def less(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
# 函数重载:定义两个版本的less函数,分别处理不同类型的输入参数,并返回布尔类型的NumPy数组

# String operations
@overload
def add(x1: U_co, x2: U_co) -> NDArray[str_]: ...
@overload
def add(x1: S_co, x2: S_co) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的add函数,分别处理字符串和字节串的输入参数,并返回字符串或字节串的NumPy数组

@overload
def multiply(a: U_co, i: i_co) -> NDArray[str_]: ...
@overload
def multiply(a: S_co, i: i_co) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的multiply函数,分别处理字符串和字节串的输入参数,并返回重复字符串或字节串的NumPy数组

@overload
def mod(a: U_co, value: Any) -> NDArray[str_]: ...
@overload
def mod(a: S_co, value: Any) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的mod函数,分别处理字符串和字节串的输入参数,并返回格式化后的字符串或字节串的NumPy数组

@overload
def capitalize(a: U_co) -> NDArray[str_]: ...
@overload
def capitalize(a: S_co) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的capitalize函数,分别处理字符串和字节串的输入参数,并返回首字母大写的字符串或字节串的NumPy数组

@overload
def center(a: U_co, width: i_co, fillchar: U_co = ...) -> NDArray[str_]: ...
@overload
def center(a: S_co, width: i_co, fillchar: S_co = ...) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的center函数,分别处理字符串和字节串的输入参数,并返回居中对齐的字符串或字节串的NumPy数组

def decode(
    a: S_co,
    encoding: None | str = ...,
    errors: None | str = ...,
) -> NDArray[str_]: ...
# decode函数:解码字节串为字符串,并返回NumPy数组

def encode(
    a: U_co,
    encoding: None | str = ...,
    errors: None | str = ...,
) -> NDArray[bytes_]: ...
# encode函数:编码字符串为字节串,并返回NumPy数组

@overload
def expandtabs(a: U_co, tabsize: i_co = ...) -> NDArray[str_]: ...
@overload
def expandtabs(a: S_co, tabsize: i_co = ...) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的expandtabs函数,分别处理字符串和字节串的输入参数,并返回扩展制表符的字符串或字节串的NumPy数组

@overload
def join(sep: U_co, seq: U_co) -> NDArray[str_]: ...
@overload
def join(sep: S_co, seq: S_co) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的join函数,分别处理字符串和字节串的输入参数,并返回连接序列的字符串或字节串的NumPy数组

@overload
def ljust(a: U_co, width: i_co, fillchar: U_co = ...) -> NDArray[str_]: ...
@overload
def ljust(a: S_co, width: i_co, fillchar: S_co = ...) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的ljust函数,分别处理字符串和字节串的输入参数,并返回左对齐的字符串或字节串的NumPy数组

@overload
def lower(a: U_co) -> NDArray[str_]: ...
@overload
def lower(a: S_co) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的lower函数,分别处理字符串和字节串的输入参数,并返回小写化的字符串或字节串的NumPy数组

@overload
def lstrip(a: U_co, chars: None | U_co = ...) -> NDArray[str_]: ...
@overload
def lstrip(a: S_co, chars: None | S_co = ...) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的lstrip函数,分别处理字符串和字节串的输入参数,并返回去除左侧空白字符的字符串或字节串的NumPy数组

@overload
def partition(a: U_co, sep: U_co) -> NDArray[str_]: ...
@overload
def partition(a: S_co, sep: S_co) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的partition函数,分别处理字符串和字节串的输入参数,并返回分割后的字符串或字节串的NumPy数组

@overload
def replace(
    a: U_co,
    old: U_co,
    new: U_co,
    count: None | i_co = ...,
) -> NDArray[str_]: ...
@overload
def replace(
    a: S_co,
    old: S_co,
    new: S_co,
    count: None | i_co = ...,
) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的replace函数,分别处理字符串和字节串的输入参数,并返回替换后的字符串或字节串的NumPy数组

@overload
def rjust(
    a: U_co,
    width: i_co,
    fillchar: U_co = ...,
) -> NDArray[str_]: ...
@overload
def rjust(
    a: S_co,
    width: i_co,
    fillchar: S_co = ...,
) -> NDArray[bytes_]: ...
# 函数重载:定义两个版本的rjust函数,分别处理字符串和字节串的输入参数,并返回右对齐的字符串或字节串的NumPy数组
    a: S_co,            # 定义变量a,类型为S_co
    width: i_co,        # 定义变量width,类型为i_co
    fillchar: S_co = ...,  # 定义变量fillchar,类型为S_co,并初始化为...
# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def rpartition(a: U_co, sep: U_co) -> NDArray[bytes_]: ...
@overload
def rpartition(a: S_co, sep: S_co) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[object_],表示函数返回一个对象数组
@overload
def rsplit(
    a: U_co,
    sep: None | U_co = ...,
    maxsplit: None | i_co = ...,
) -> NDArray[object_]: ...
@overload
def rsplit(
    a: S_co,
    sep: None | S_co = ...,
    maxsplit: None | i_co = ...,
) -> NDArray[object_]: ...

# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def rstrip(a: U_co, chars: None | U_co = ...) -> NDArray[bytes_]: ...
@overload
def rstrip(a: S_co, chars: None | S_co = ...) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[object_],表示函数返回一个对象数组
@overload
def split(
    a: U_co,
    sep: None | U_co = ...,
    maxsplit: None | i_co = ...,
) -> NDArray[object_]: ...
@overload
def split(
    a: S_co,
    sep: None | S_co = ...,
    maxsplit: None | i_co = ...,
) -> NDArray[object_]: ...

# 返回类型注释为 NDArray[object_],表示函数返回一个对象数组
@overload
def splitlines(a: U_co, keepends: None | b_co = ...) -> NDArray[object_]: ...
@overload
def splitlines(a: S_co, keepends: None | b_co = ...) -> NDArray[object_]: ...

# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def strip(a: U_co, chars: None | U_co = ...) -> NDArray[bytes_]: ...
@overload
def strip(a: S_co, chars: None | S_co = ...) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def swapcase(a: U_co) -> NDArray[bytes_]: ...
@overload
def swapcase(a: S_co) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def title(a: U_co) -> NDArray[bytes_]: ...
@overload
def title(a: S_co) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def translate(
    a: U_co,
    table: U_co,
    deletechars: None | U_co = ...,
) -> NDArray[bytes_]: ...
@overload
def translate(
    a: S_co,
    table: S_co,
    deletechars: None | S_co = ...,
) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def upper(a: U_co) -> NDArray[bytes_]: ...
@overload
def upper(a: S_co) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[bytes_],表示函数返回一个字节串数组
@overload
def zfill(a: U_co, width: i_co) -> NDArray[bytes_]: ...
@overload
def zfill(a: S_co, width: i_co) -> NDArray[bytes_]: ...

# 返回类型注释为 NDArray[int_],表示函数返回一个整数数组
# 字符串信息统计
@overload
def count(
    a: U_co,
    sub: U_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...
@overload
def count(
    a: S_co,
    sub: S_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...

# 返回类型注释为 NDArray[np.bool],表示函数返回一个布尔值数组
@overload
def endswith(
    a: U_co,
    suffix: U_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[np.bool]: ...
@overload
def endswith(
    a: S_co,
    suffix: S_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[np.bool]: ...

# 返回类型注释为 NDArray[int_],表示函数返回一个整数数组
@overload
def find(
    a: U_co,
    sub: U_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...
@overload
def find(
    a: S_co,
    sub: S_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...

# 返回类型注释为 NDArray[int_],表示函数返回一个整数数组
@overload
def index(
    a: U_co,
    sub: U_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...
@overload
def index(
    a: S_co,
    sub: S_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...

# 返回类型注释为 NDArray[np.bool],表示函数返回一个布尔值数组
def isalpha(a: U_co | S_co) -> NDArray[np.bool]: ...

# 返回类型注释为 NDArray[np.bool],表示函数返回一个布尔值数组
def isalnum(a: U_co | S_co) -> NDArray[np.bool]: ...
# 判断参数 a 是否是一个可接受的 Unicode 字符,并返回一个布尔值数组
def isdecimal(a: U_co) -> NDArray[np.bool]: ...

# 判断参数 a 是否是一个可接受的 Unicode 数字,并返回一个布尔值数组
def isdigit(a: U_co | S_co) -> NDArray[np.bool]: ...

# 判断参数 a 是否是小写字母,并返回一个布尔值数组
def islower(a: U_co | S_co) -> NDArray[np.bool]: ...

# 判断参数 a 是否是一个可接受的 Unicode 数字,并返回一个布尔值数组
def isnumeric(a: U_co) -> NDArray[np.bool]: ...

# 判断参数 a 是否是空格,并返回一个布尔值数组
def isspace(a: U_co | S_co) -> NDArray[np.bool]: ...

# 判断参数 a 是否符合标题化格式,并返回一个布尔值数组
def istitle(a: U_co | S_co) -> NDArray[np.bool]: ...

# 判断参数 a 是否是大写字母,并返回一个布尔值数组
def isupper(a: U_co | S_co) -> NDArray[np.bool]: ...

# Overload 1 and 2: 在字符串或字节串中查找子串 sub,从后往前搜索,返回索引数组
# Overload 3 and 4: 在对象中查找子串 sub,从后往前搜索,返回索引数组
@overload
def rfind(
    a: U_co,
    sub: U_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...

@overload
def rfind(
    a: S_co,
    sub: S_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...

# Overload 1 and 2: 在字符串或字节串中查找子串 sub,从后往前搜索,返回索引数组
# Overload 3 and 4: 在对象中查找子串 sub,从后往前搜索,返回索引数组
@overload
def rindex(
    a: U_co,
    sub: U_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...

@overload
def rindex(
    a: S_co,
    sub: S_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[int_]: ...

# Overload 1 and 2: 检查字符串或字节串是否以指定前缀开头,并返回布尔值数组
# Overload 3 and 4: 检查对象是否以指定前缀开头,并返回布尔值数组
@overload
def startswith(
    a: U_co,
    prefix: U_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[np.bool]: ...

@overload
def startswith(
    a: S_co,
    prefix: S_co,
    start: i_co = ...,
    end: None | i_co = ...,
) -> NDArray[np.bool]: ...

# 返回字符串或字节串的长度作为整数数组
def str_len(A: U_co | S_co) -> NDArray[int_]: ...

# Overload 1 and 2: 根据对象创建字符数组,可以指定是否复制和字节串的大小
# Overload 3: 对于具有 unicode=False 的任意对象,返回字节串数组
# Overload 4: 对于具有 unicode=True 的任意对象,返回字符串数组
@overload
def array(
    obj: U_co,
    itemsize: None | int = ...,
    copy: bool = ...,
    unicode: L[False] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[str_]: ...

@overload
def array(
    obj: S_co,
    itemsize: None | int = ...,
    copy: bool = ...,
    unicode: L[False] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[bytes_]: ...

@overload
def array(
    obj: object,
    itemsize: None | int = ...,
    copy: bool = ...,
    unicode: L[False] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[bytes_]: ...

@overload
def array(
    obj: object,
    itemsize: None | int = ...,
    copy: bool = ...,
    unicode: L[True] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[str_]: ...

# 根据对象创建字符数组,可以指定是否复制和字节串的大小
@overload
def asarray(
    obj: U_co,
    itemsize: None | int = ...,
    unicode: L[False] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[str_]: ...

@overload
def asarray(
    obj: S_co,
    itemsize: None | int = ...,
    unicode: L[False] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[bytes_]: ...

@overload
def asarray(
    obj: object,
    itemsize: None | int = ...,
    unicode: L[False] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[bytes_]: ...

@overload
def asarray(
    obj: object,
    itemsize: None | int = ...,
    unicode: L[True] = ...,
    order: _OrderKACF = ...,
) -> _CharArray[str_]: ...

.\numpy\numpy\_core\einsumfunc.py

"""
Implementation of optimized einsum.

"""
import itertools  # 导入 itertools 模块,用于生成迭代器和循环的工具
import operator   # 导入 operator 模块,提供了对内置操作符的函数接口

from numpy._core.multiarray import c_einsum   # 导入 numpy 中的 c_einsum 函数
from numpy._core.numeric import asanyarray, tensordot   # 导入 numpy 中的数组处理函数
from numpy._core.overrides import array_function_dispatch   # 导入 numpy 中的函数装饰器

__all__ = ['einsum', 'einsum_path']   # 设置模块的公开接口

# importing string for string.ascii_letters would be too slow
# the first import before caching has been measured to take 800 µs (#23777)
einsum_symbols = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'   # 定义字符串,表示可能出现的全部字母作为 einsum 的符号
einsum_symbols_set = set(einsum_symbols)   # 将所有可能的符号转化为集合,以供快速查找


def _flop_count(idx_contraction, inner, num_terms, size_dictionary):
    """
    Computes the number of FLOPS in the contraction.

    Parameters
    ----------
    idx_contraction : iterable
        The indices involved in the contraction
    inner : bool
        Does this contraction require an inner product?
    num_terms : int
        The number of terms in a contraction
    size_dictionary : dict
        The size of each of the indices in idx_contraction

    Returns
    -------
    flop_count : int
        The total number of FLOPS required for the contraction.

    Examples
    --------

    >>> _flop_count('abc', False, 1, {'a': 2, 'b':3, 'c':5})
    30

    >>> _flop_count('abc', True, 2, {'a': 2, 'b':3, 'c':5})
    60

    """
    overall_size = _compute_size_by_dict(idx_contraction, size_dictionary)   # 计算给定指标集合的总大小
    op_factor = max(1, num_terms - 1)   # 计算操作因子,考虑到合并操作的次数
    if inner:
        op_factor += 1   # 如果需要内积,增加操作因子

    return overall_size * op_factor   # 返回总的 FLOPS 数量


def _compute_size_by_dict(indices, idx_dict):
    """
    Computes the product of the elements in indices based on the dictionary
    idx_dict.

    Parameters
    ----------
    indices : iterable
        Indices to base the product on.
    idx_dict : dictionary
        Dictionary of index sizes

    Returns
    -------
    ret : int
        The resulting product.

    Examples
    --------
    >>> _compute_size_by_dict('abbc', {'a': 2, 'b':3, 'c':5})
    90

    """
    ret = 1   # 初始化结果为1
    for i in indices:
        ret *= idx_dict[i]   # 根据索引字典计算给定索引集合的乘积
    return ret   # 返回计算结果


def _find_contraction(positions, input_sets, output_set):
    """
    Finds the contraction for a given set of input and output sets.

    Parameters
    ----------
    positions : iterable
        Integer positions of terms used in the contraction.
    input_sets : list
        List of sets that represent the lhs side of the einsum subscript
    output_set : set
        Set that represents the rhs side of the overall einsum subscript

    Returns
    -------
    new_result : set
        The indices of the resulting contraction
    remaining : list
        List of sets that have not been contracted, the new set is appended to
        the end of this list
    idx_removed : set
        Indices removed from the entire contraction
    idx_contraction : set
        The indices used in the current contraction

    Examples
    --------

    # A simple dot product test case
    >>> pos = (0, 1)
    >>> isets = [set('ab'), set('bc')]
    >>> oset = set('ac')

    """
    # 初始化空集合,用于记录收缩的索引集合
    idx_contract = set()
    # 复制输出集合,以确保不改变原始数据
    idx_remain = output_set.copy()
    # 初始化空列表,用于存储剩余的集合
    remaining = []
    
    # 遍历输入集合的索引和值
    for ind, value in enumerate(input_sets):
        # 如果当前索引在收缩位置集合中
        if ind in positions:
            # 将当前集合并入收缩的索引集合中
            idx_contract |= value
        else:
            # 否则将当前集合加入剩余集合列表中
            remaining.append(value)
            # 并将当前集合并入剩余的索引集合中
            idx_remain |= value
    
    # 计算新的结果集合,为剩余索引集合和收缩索引集合的交集
    new_result = idx_remain & idx_contract
    # 计算从收缩索引集合中移除的元素
    idx_removed = (idx_contract - new_result)
    # 将新结果集合添加到剩余集合列表中
    remaining.append(new_result)
    
    # 返回四个结果:新的结果集合、剩余集合列表、移除的索引集合、收缩的索引集合
    return (new_result, remaining, idx_removed, idx_contract)
def _optimal_path(input_sets, output_set, idx_dict, memory_limit):
    """
    Computes all possible pair contractions, sieves the results based
    on ``memory_limit`` and returns the lowest cost path. This algorithm
    scales factorial with respect to the elements in the list ``input_sets``.

    Parameters
    ----------
    input_sets : list
        List of sets that represent the lhs side of the einsum subscript
    output_set : set
        Set that represents the rhs side of the overall einsum subscript
    idx_dict : dictionary
        Dictionary of index sizes
    memory_limit : int
        The maximum number of elements in a temporary array

    Returns
    -------
    path : list
        The optimal contraction order within the memory limit constraint.

    Examples
    --------
    >>> isets = [set('abd'), set('ac'), set('bdc')]
    >>> oset = set()
    >>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4}
    >>> _optimal_path(isets, oset, idx_sizes, 5000)
    [(0, 2), (0, 1)]
    """

    # Initialize with the full set of input sets
    full_results = [(0, [], input_sets)]

    # Iterate through all possible contractions
    for iteration in range(len(input_sets) - 1):
        iter_results = []

        # Compute all unique pairs
        for curr in full_results:
            cost, positions, remaining = curr
            for con in itertools.combinations(
                range(len(input_sets) - iteration), 2
            ):

                # Find the contraction and associated details
                cont = _find_contraction(con, remaining, output_set)
                new_result, new_input_sets, idx_removed, idx_contract = cont

                # Calculate size of new result and check against memory limit
                new_size = _compute_size_by_dict(new_result, idx_dict)
                if new_size > memory_limit:
                    continue

                # Calculate total cost of this contraction path
                total_cost = cost + _flop_count(
                    idx_contract, idx_removed, len(con), idx_dict
                )
                new_pos = positions + [con]
                iter_results.append((total_cost, new_pos, new_input_sets))

        # Update full results with new iteration results
        if iter_results:
            full_results = iter_results
        else:
            # If no valid contractions found, return best path plus remaining contractions
            path = min(full_results, key=lambda x: x[0])[1]
            path += [tuple(range(len(input_sets) - iteration))]
            return path

    # If no valid contractions found throughout all iterations, return single einsum contraction
    if len(full_results) == 0:
        return [tuple(range(len(input_sets)))]

    # Return the optimal path found
    path = min(full_results, key=lambda x: x[0])[1]
    return path


def _parse_possible_contraction(
        positions, input_sets, output_set, idx_dict, 
        memory_limit, path_cost, naive_cost
    ):
    """Compute the cost (removed size + flops) and resultant indices for
    performing the contraction specified by ``positions``.

    Parameters
    ----------
    positions : list
        List of pairs specifying contraction positions
    input_sets : list
        List of sets representing lhs side of the einsum subscript
    output_set : set
        Set representing rhs side of the einsum subscript
    idx_dict : dict
        Dictionary of index sizes
    memory_limit : int
        Maximum number of elements in a temporary array
    path_cost : int
        Current cost of the contraction path
    naive_cost : int
        Naive cost estimate

    Returns
    -------
    tuple
        Tuple containing the resultant indices, input sets after contraction,
        indices removed, and indices contracted
    """
    # positions: tuple of int
    #     The locations of the proposed tensors to contract.
    # input_sets: list of sets
    #     The indices found on each tensor.
    # output_set: set
    #     The output indices of the expression.
    # idx_dict: dict
    #     Mapping of each index to its size.
    # memory_limit: int
    #     The total allowed size for an intermediary tensor.
    # path_cost: int
    #     The contraction cost so far.
    # naive_cost: int
    #     The cost of the unoptimized expression.
    # Returns
    # -------
    # cost: (int, int)
    #     A tuple containing the size of any indices removed, and the flop cost.
    # positions: tuple of int
    #     The locations of the proposed tensors to contract.
    # new_input_sets: list of sets
    #     The resulting new list of indices if this proposed contraction
    #     is performed.
    
    # Find the contraction based on provided positions and input/output sets
    contract = _find_contraction(positions, input_sets, output_set)
    idx_result, new_input_sets, idx_removed, idx_contract = contract

    # Compute the size of the resulting tensor based on idx_result and idx_dict
    new_size = _compute_size_by_dict(idx_result, idx_dict)
    
    # Check if the computed size exceeds the memory limit; if so, return None
    if new_size > memory_limit:
        return None

    # Calculate the sizes of the tensors before contraction
    old_sizes = (
        _compute_size_by_dict(input_sets[p], idx_dict) for p in positions
    )
    removed_size = sum(old_sizes) - new_size

    # Compute the flop count based on the contraction indices and idx_dict
    cost = _flop_count(idx_contract, idx_removed, len(positions), idx_dict)
    
    # Create a tuple for sorting purposes based on removed_size and cost
    sort = (-removed_size, cost)

    # Check if the total path cost plus the current cost exceeds naive_cost; if so, return None
    if (path_cost + cost) > naive_cost:
        return None

    # Return the result of the contraction as a list containing the sort tuple, positions, and new_input_sets
    return [sort, positions, new_input_sets]
def _update_other_results(results, best):
    """Update the positions and provisional input_sets of ``results``
    based on performing the contraction result ``best``. Remove any
    involving the tensors contracted.
    
    Parameters
    ----------
    results : list
        List of contraction results produced by 
        ``_parse_possible_contraction``.
    best : list
        The best contraction of ``results`` i.e. the one that
        will be performed.
        
    Returns
    -------
    mod_results : list
        The list of modified results, updated with outcome of
        ``best`` contraction.
    """

    best_con = best[1]  # Extract the contraction indices from the best contraction result
    bx, by = best_con    # Unpack the indices into bx and by
    mod_results = []     # Initialize an empty list to store modified results

    for cost, (x, y), con_sets in results:
        # Ignore results involving tensors just contracted
        if x in best_con or y in best_con:
            continue
        
        # Update the input_sets by removing contracted indices
        del con_sets[by - int(by > x) - int(by > y)]
        del con_sets[bx - int(bx > x) - int(bx > y)]
        con_sets.insert(-1, best[2][-1])  # Insert the result of the best contraction at the end of con_sets
        
        # Update the position indices based on the performed contraction
        mod_con = x - int(x > bx) - int(x > by), y - int(y > bx) - int(y > by)
        mod_results.append((cost, mod_con, con_sets))  # Append the modified result to mod_results list

    return mod_results  # Return the list of modified results


def _greedy_path(input_sets, output_set, idx_dict, memory_limit):
    """
    Finds the path by contracting the best pair until the input list is
    exhausted. The best pair is found by minimizing the tuple
    ``(-prod(indices_removed), cost)``.  What this amounts to is prioritizing
    matrix multiplication or inner product operations, then Hadamard like
    operations, and finally outer operations. Outer products are limited by
    ``memory_limit``. This algorithm scales cubically with respect to the
    number of elements in the list ``input_sets``.
    
    Parameters
    ----------
    input_sets : list
        List of sets that represent the lhs side of the einsum subscript
    output_set : set
        Set that represents the rhs side of the overall einsum subscript
    idx_dict : dictionary
        Dictionary of index sizes
    memory_limit : int
        The maximum number of elements in a temporary array
    
    Returns
    -------
    path : list
        The greedy contraction order within the memory limit constraint.
    
    Examples
    --------
    >>> isets = [set('abd'), set('ac'), set('bdc')]
    >>> oset = set()
    >>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4}
    >>> _greedy_path(isets, oset, idx_sizes, 5000)
    [(0, 2), (0, 1)]
    """
    
    # Handle trivial cases that leaked through
    if len(input_sets) == 1:
        return [(0,)]
    elif len(input_sets) == 2:
        return [(0, 1)]
    
    # Build up a naive cost
    contract = _find_contraction(
        range(len(input_sets)), input_sets, output_set
    )
    idx_result, new_input_sets, idx_removed, idx_contract = contract
    naive_cost = _flop_count(
        idx_contract, idx_removed, len(input_sets), idx_dict
    )
    
    # Initially iterate over all pairs
    # 生成输入集合中元素的所有两两组合的迭代器
    comb_iter = itertools.combinations(range(len(input_sets)), 2)
    # 已知的可以收缩的对的列表
    known_contractions = []

    # 路径的总成本和路径的列表初始化
    path_cost = 0
    path = []

    # 对输入集合进行迭代,执行 len(input_sets) - 1 次
    for iteration in range(len(input_sets) - 1):

        # 在第一步遍历所有对,在后续步骤只遍历先前找到的对
        for positions in comb_iter:

            # 如果两个集合是不相交的,则忽略
            if input_sets[positions[0]].isdisjoint(input_sets[positions[1]]):
                continue

            # 调用函数尝试解析可能的收缩操作
            result = _parse_possible_contraction(
                positions, input_sets, output_set, idx_dict,
                memory_limit, path_cost, naive_cost
            )
            # 如果成功找到了收缩操作,则将其加入已知的收缩列表中
            if result is not None:
                known_contractions.append(result)

        # 如果没有找到内部收缩操作,则重新扫描包括外部乘积的对
        if len(known_contractions) == 0:

            # 检查包括外部乘积的所有对
            for positions in itertools.combinations(
                range(len(input_sets)), 2
            ):
                result = _parse_possible_contraction(
                    positions, input_sets, output_set, idx_dict,
                    memory_limit, path_cost, naive_cost
                )
                if result is not None:
                    known_contractions.append(result)

            # 如果仍然没有找到剩余的收缩操作,则默认回到 einsum 的行为方式
            if len(known_contractions) == 0:
                # 将整个集合作为一个路径元素添加到路径中
                path.append(tuple(range(len(input_sets))))
                break

        # 根据第一个索引排序已知的收缩操作列表
        best = min(known_contractions, key=lambda x: x[0])

        # 将尽可能多未使用的收缩操作传播到下一次迭代
        known_contractions = _update_other_results(known_contractions, best)

        # 下一次迭代仅计算新张量参与的收缩操作
        # 所有其他的收缩操作已经被处理过了
        input_sets = best[2]
        new_tensor_pos = len(input_sets) - 1
        # 生成新的两两组合迭代器,只包含新张量与其他张量的组合
        comb_iter = ((i, new_tensor_pos) for i in range(new_tensor_pos))

        # 更新路径和总成本
        path.append(best[1])
        path_cost += best[0][1]

    # 返回最终计算出的路径
    return path
# 定义名为 `_can_dot` 的函数,用于判断是否可以使用 BLAS(如 `np.tensordot`)进行张量点积操作,并且判断其是否有效。
def _can_dot(inputs, result, idx_removed):
    """
    Checks if we can use BLAS (np.tensordot) call and its beneficial to do so.

    Parameters
    ----------
    inputs : list of str
        Specifies the subscripts for summation.
    result : str
        Resulting summation.
    idx_removed : set
        Indices that are removed in the summation

    Returns
    -------
    type : bool
        Returns true if BLAS should and can be used, else False

    Notes
    -----
    If the operations is BLAS level 1 or 2 and is not already aligned
    we default back to einsum as the memory movement to copy is more
    costly than the operation itself.

    Examples
    --------

    # Standard GEMM operation
    >>> _can_dot(['ij', 'jk'], 'ik', set('j'))
    True

    # Can use the standard BLAS, but requires odd data movement
    >>> _can_dot(['ijj', 'jk'], 'ik', set('j'))
    False

    # DDOT where the memory is not aligned
    >>> _can_dot(['ijk', 'ikj'], '', set('ijk'))
    False

    """

    # 检查所有 `dot` 调用是否移除了索引
    if len(idx_removed) == 0:
        return False

    # BLAS 只能处理两个操作数
    if len(inputs) != 2:
        return False

    # 分别获取左右两个输入字符串
    input_left, input_right = inputs

    # 遍历输入字符串中的字符集合
    for c in set(input_left + input_right):
        # 不能处理同一输入中的重复索引或超过两个总数的情况
        nl, nr = input_left.count(c), input_right.count(c)
        if (nl > 1) or (nr > 1) or (nl + nr > 2):
            return False

        # 不能进行隐式求和或维度折叠,例如:
        # "ab,bc->c"(隐式求和 'a')
        # "ab,ca->ca"(取 'a' 的对角线)
        if nl + nr - 1 == int(c in result):
            return False

    # 创建几个临时集合
    set_left = set(input_left)
    set_right = set(input_right)
    keep_left = set_left - idx_removed
    keep_right = set_right - idx_removed
    rs = len(idx_removed)

    # 判断是否为 DOT、GEMV 或 GEMM 操作

    # 对齐数据的 DDOT 操作
    if input_left == input_right:
        return True

    # 不对齐数据的 DDOT 操作(建议使用 einsum)
    if set_left == set_right:
        return False

    # 处理四种可能的(对齐的)GEMV 或 GEMM 情况

    # GEMM 或 GEMV 操作,不转置
    if input_left[-rs:] == input_right[:rs]:
        return True

    # GEMM 或 GEMV 操作,两者都转置
    if input_left[:rs] == input_right[-rs:]:
        return True

    # GEMM 或 GEMV 操作,右侧转置
    if input_left[-rs:] == input_right[-rs:]:
        return True

    # GEMM 或 GEMV 操作,左侧转置
    if input_left[:rs] == input_right[:rs]:
        return True

    # 如果需要复制数据,则 einsum 比 GEMV 更快
    if not keep_left or not keep_right:
        return False

    # 我们是矩阵-矩阵乘积,但需要复制数据
    return True
    input_strings : str
        Parsed input strings
    output_string : str
        Parsed output string
    operands : list of array_like
        The operands to use in the numpy contraction

    Examples
    --------
    The operand list is simplified to reduce printing:

    >>> np.random.seed(123)
    >>> a = np.random.rand(4, 4)
    >>> b = np.random.rand(4, 4, 4)
    >>> _parse_einsum_input(('...a,...a->...', a, b))
    ('za,xza', 'xz', [a, b]) # may vary

    >>> _parse_einsum_input((a, [Ellipsis, 0], b, [Ellipsis, 0]))
    ('za,xza', 'xz', [a, b]) # may vary
    """

    # Check if there are no input operands, raise an error
    if len(operands) == 0:
        raise ValueError("No input operands")

    # If the first operand is a string, parse subscripts and validate characters
    if isinstance(operands[0], str):
        subscripts = operands[0].replace(" ", "")
        operands = [asanyarray(v) for v in operands[1:]]

        # Ensure all characters in subscripts are valid
        for s in subscripts:
            if s in '.,->':
                continue
            if s not in einsum_symbols:
                raise ValueError("Character %s is not a valid symbol." % s)

    else:
        tmp_operands = list(operands)
        operand_list = []
        subscript_list = []

        # Parse each pair of operand and its subscript
        for p in range(len(operands) // 2):
            operand_list.append(tmp_operands.pop(0))
            subscript_list.append(tmp_operands.pop(0))

        output_list = tmp_operands[-1] if len(tmp_operands) else None
        operands = [asanyarray(v) for v in operand_list]
        subscripts = ""
        last = len(subscript_list) - 1

        # Construct the subscripts string based on the parsed subscripts
        for num, sub in enumerate(subscript_list):
            for s in sub:
                if s is Ellipsis:
                    subscripts += "..."
                else:
                    try:
                        s = operator.index(s)
                    except TypeError as e:
                        raise TypeError(
                            "For this input type lists must contain "
                            "either int or Ellipsis"
                        ) from e
                    subscripts += einsum_symbols[s]
            if num != last:
                subscripts += ","

        # If there is an output list, append it to the subscripts string
        if output_list is not None:
            subscripts += "->"
            for s in output_list:
                if s is Ellipsis:
                    subscripts += "..."
                else:
                    try:
                        s = operator.index(s)
                    except TypeError as e:
                        raise TypeError(
                            "For this input type lists must contain "
                            "either int or Ellipsis"
                        ) from e
                    subscripts += einsum_symbols[s]

    # Check for proper '->' syntax in subscripts
    if ("-" in subscripts) or (">" in subscripts):
        invalid = (subscripts.count("-") > 1) or (subscripts.count(">") > 1)
        if invalid or (subscripts.count("->") != 1):
            raise ValueError("Subscripts can only contain one '->'.")

    # Parse ellipses
    # 如果子脚本中包含".",则去除"."、","和"->"后,得到使用过的字符集合
    used = subscripts.replace(".", "").replace(",", "").replace("->", "")
    # 计算未使用的字符集合,即 einsum_symbols_set 减去已使用的字符集合
    unused = list(einsum_symbols_set - set(used))
    # 将未使用的字符集合转换为字符串
    ellipse_inds = "".join(unused)
    # 初始化最长 ellipsis 的长度为 0
    longest = 0

    # 如果子脚本包含"->",则按"->"分割输入和输出子脚本
    if "->" in subscripts:
        input_tmp, output_sub = subscripts.split("->")
        split_subscripts = input_tmp.split(",")
        out_sub = True
    else:
        split_subscripts = subscripts.split(',')
        out_sub = False

    # 遍历分割后的子脚本列表
    for num, sub in enumerate(split_subscripts):
        # 如果子脚本中包含".",并且不符合 ellipsis 的规则,则引发 ValueError
        if "." in sub:
            if (sub.count(".") != 3) or (sub.count("...") != 1):
                raise ValueError("Invalid Ellipses.")

            # 计算 ellipsis 的长度,考虑操作数的形状
            if operands[num].shape == ():
                ellipse_count = 0
            else:
                ellipse_count = max(operands[num].ndim, 1)
                ellipse_count -= (len(sub) - 3)

            # 更新最长 ellipsis 的长度
            if ellipse_count > longest:
                longest = ellipse_count

            # 检查 ellipsis 的长度是否合法
            if ellipse_count < 0:
                raise ValueError("Ellipses lengths do not match.")
            elif ellipse_count == 0:
                split_subscripts[num] = sub.replace('...', '')
            else:
                # 替换 ellipsis 为未使用字符集合中对应长度的字符
                rep_inds = ellipse_inds[-ellipse_count:]
                split_subscripts[num] = sub.replace('...', rep_inds)

    # 将更新后的子脚本列表重新拼接为字符串
    subscripts = ",".join(split_subscripts)

    # 根据最长 ellipsis 的长度确定输出 ellipsis 字符串
    if longest == 0:
        out_ellipse = ""
    else:
        out_ellipse = ellipse_inds[-longest:]

    # 如果有输出子脚本,则根据最长 ellipsis 更新输出子脚本
    if out_sub:
        subscripts += "->" + output_sub.replace("...", out_ellipse)
    else:
        # 处理无输出子脚本时的特殊情况
        output_subscript = ""
        tmp_subscripts = subscripts.replace(",", "")
        # 检查并构建正常的输出子脚本
        for s in sorted(set(tmp_subscripts)):
            if s not in (einsum_symbols):
                raise ValueError("Character %s is not a valid symbol." % s)
            if tmp_subscripts.count(s) == 1:
                output_subscript += s
        # 从正常的输出子脚本中删除输出 ellipsis 的字符,得到正常的索引字符
        normal_inds = ''.join(sorted(set(output_subscript) - set(out_ellipse)))
        # 更新子脚本字符串,包括输出 ellipsis 和正常的索引字符
        subscripts += "->" + out_ellipse + normal_inds

# 如果子脚本中包含"->",则按"->"分割输入子脚本和输出子脚本
if "->" in subscripts:
    input_subscripts, output_subscript = subscripts.split("->")
else:
    # 如果没有输出子脚本,则将整个子脚本作为输入子脚本
    input_subscripts = subscripts

# 确保输出子脚本中的字符都在输入子脚本中存在
    # 遍历输出下标字符串中的每个字符
    for char in output_subscript:
        # 检查字符在输出下标字符串中出现的次数,应该为1次,否则引发值错误异常
        if output_subscript.count(char) != 1:
            raise ValueError("Output character %s appeared more than once in "
                             "the output." % char)
        # 检查字符是否存在于输入下标字符串中,否则引发值错误异常
        if char not in input_subscripts:
            raise ValueError("Output character %s did not appear in the input"
                             % char)

    # 确保输入下标字符串的逗号分隔的子字符串数量等于操作数的数量
    if len(input_subscripts.split(',')) != len(operands):
        raise ValueError("Number of einsum subscripts must be equal to the "
                         "number of operands.")

    # 返回元组,包含输入下标字符串、输出下标字符串和操作数列表
    return (input_subscripts, output_subscript, operands)
# 根据传入的参数来分发 einsum_path 函数调用,选择合适的优化方法和路径
def _einsum_path_dispatcher(*operands, optimize=None, einsum_call=None):
    # 注意:从技术上讲,我们应该只对类数组的参数进行分发,而不是对子脚本(以字符串形式给出)进行分发。
    # 但是,将操作数分开为数组/子脚本有些复杂/慢(考虑到 einsum 的两种支持签名),
    # 所以作为一种实际上的快捷方式,我们对所有内容进行分发。
    # 字符串将被忽略以用于分发,因为它们不定义 __array_function__。
    return operands


# 使用 numpy 提供的 array_function_dispatch 装饰器,将 _einsum_path_dispatcher 函数注册为 einsum_path 的分发函数
@array_function_dispatch(_einsum_path_dispatcher, module='numpy')
def einsum_path(*operands, optimize='greedy', einsum_call=False):
    """
    einsum_path(subscripts, *operands, optimize='greedy')

    根据考虑中间数组的创建来评估 einsum 表达式的最低成本收缩顺序。

    Parameters
    ----------
    subscripts : str
        指定求和的下标。
    *operands : list of array_like
        这些是操作的数组。
    optimize : {bool, list, tuple, 'greedy', 'optimal'}
        选择路径的类型。如果提供了一个元组,假定第二个参数是所创建的最大中间大小。
        如果只提供了一个参数,则使用最大输入或输出数组大小作为最大中间大小。

        * 如果给定以 ``einsum_path`` 开头的列表,将其用作收缩路径
        * 如果为 False,不进行优化
        * 如果为 True,默认使用 'greedy' 算法
        * 'optimal' 一种算法,通过组合地探索所有可能的张量收缩方式并选择成本最低的路径。随着收缩项数的增加呈指数级增长。
        * 'greedy' 一种算法,在每一步选择最佳的对子收缩。实际上,此算法在每一步搜索最大的内部、哈达玛尔乘积,然后外积。随着收缩项数的增加呈立方级增长。对于大多数收缩,与 'optimal' 路径等效。

        默认为 'greedy'。

    Returns
    -------
    path : list of tuples
        einsum 路径的列表表示。
    string_repr : str
        einsum 路径的可打印表示。

    Notes
    -----
    结果路径指示应首先收缩输入收缩的哪些项,然后将此收缩的结果附加到收缩列表的末尾。
    然后可以遍历此列表,直到所有中间收缩完成。

    See Also
    --------
    einsum, linalg.multi_dot

    Examples
    --------

    我们可以从一个链式点乘的例子开始。在这种情况下,首先收缩 ``b`` 和 ``c`` 张量是最优的,由路径的第一个元素 ``(1, 2)`` 表示。
    收缩的结果张量被添加到末尾
    """
    """
    of the contraction and the remaining contraction ``(0, 1)`` is then
    completed.

    >>> np.random.seed(123)
    >>> a = np.random.rand(2, 2)
    >>> b = np.random.rand(2, 5)
    >>> c = np.random.rand(5, 2)
    >>> path_info = np.einsum_path('ij,jk,kl->il', a, b, c, optimize='greedy')
    >>> print(path_info[0])
    ['einsum_path', (1, 2), (0, 1)]
    >>> print(path_info[1])
      Complete contraction:  ij,jk,kl->il # may vary
             Naive scaling:  4
         Optimized scaling:  3
          Naive FLOP count:  1.600e+02
      Optimized FLOP count:  5.600e+01
       Theoretical speedup:  2.857
      Largest intermediate:  4.000e+00 elements
    -------------------------------------------------------------------------
    scaling                  current                                remaining
    -------------------------------------------------------------------------
       3                   kl,jk->jl                                ij,jl->il
       3                   jl,ij->il                                   il->il


    A more complex index transformation example.

    >>> I = np.random.rand(10, 10, 10, 10)
    >>> C = np.random.rand(10, 10)
    >>> path_info = np.einsum_path('ea,fb,abcd,gc,hd->efgh', C, C, I, C, C,
    ...                            optimize='greedy')

    >>> print(path_info[0])
    ['einsum_path', (0, 2), (0, 3), (0, 2), (0, 1)]
    >>> print(path_info[1]) 
      Complete contraction:  ea,fb,abcd,gc,hd->efgh # may vary
             Naive scaling:  8
         Optimized scaling:  5
          Naive FLOP count:  8.000e+08
      Optimized FLOP count:  8.000e+05
       Theoretical speedup:  1000.000
      Largest intermediate:  1.000e+04 elements
    --------------------------------------------------------------------------
    scaling                  current                                remaining
    --------------------------------------------------------------------------
       5               abcd,ea->bcde                      fb,gc,hd,bcde->efgh
       5               bcde,fb->cdef                         gc,hd,cdef->efgh
       5               cdef,gc->defg                            hd,defg->efgh
       5               defg,hd->efgh                               efgh->efgh
    """

    # Figure out what the path really is
    path_type = optimize  # Assign the value of 'optimize' to 'path_type'

    if path_type is True:  # Check if 'path_type' is exactly True
        path_type = 'greedy'  # Set 'path_type' to 'greedy' if it is True

    if path_type is None:  # Check if 'path_type' is exactly None
        path_type = False  # Set 'path_type' to False if it is None

    explicit_einsum_path = False  # Initialize a boolean flag 'explicit_einsum_path' to False
    memory_limit = None  # Initialize 'memory_limit' to None

    # No optimization or a named path algorithm
    if (path_type is False) or isinstance(path_type, str):  # Check if 'path_type' is False or a string
        pass  # If so, do nothing

    # Given an explicit path
    elif len(path_type) and (path_type[0] == 'einsum_path'):  # Check if 'path_type' has length and starts with 'einsum_path'
        explicit_einsum_path = True  # Set 'explicit_einsum_path' to True

    # Path tuple with memory limit
    elif ((len(path_type) == 2) and isinstance(path_type[0], str) and
            isinstance(path_type[1], (int, float))):  # Check if 'path_type' is a tuple with specific types and length
        memory_limit = int(path_type[1])  # Set 'memory_limit' to the integer value of the second element in 'path_type'
        path_type = path_type[0]  # Update 'path_type' to the first element in 'path_type'
    ```
    else:
        raise TypeError("Did not understand the path: %s" % str(path_type))
    # 如果路径类型不被理解,则抛出类型错误异常

    # Hidden option, only einsum should call this
    einsum_call_arg = einsum_call
    # 隐藏选项,只有 einsum 应该调用这个

    # Python side parsing
    input_subscripts, output_subscript, operands = (
        _parse_einsum_input(operands)
    )
    # 解析输入,获取输入子标记、输出子标记以及操作数

    # Build a few useful list and sets
    input_list = input_subscripts.split(',')
    # 将输入子标记拆分为列表
    input_sets = [set(x) for x in input_list]
    # 创建输入子标记的集合列表
    output_set = set(output_subscript)
    # 创建输出子标记的集合
    indices = set(input_subscripts.replace(',', ''))
    # 获取所有索引的集合

    # Get length of each unique dimension and ensure all dimensions are correct
    dimension_dict = {}
    # 创建维度字典
    broadcast_indices = [[] for x in range(len(input_list))]
    # 创建广播索引的列表

    for tnum, term in enumerate(input_list):
        sh = operands[tnum].shape
        # 获取操作数的形状
        if len(sh) != len(term):
            raise ValueError("Einstein sum subscript %s does not contain the "
                             "correct number of indices for operand %d."
                             % (input_subscripts[tnum], tnum))
        # 如果子标记中的索引数量与操作数的维度不匹配,则引发值错误异常
        for cnum, char in enumerate(term):
            dim = sh[cnum]
            # 获取维度

            # Build out broadcast indices
            if dim == 1:
                broadcast_indices[tnum].append(char)
            # 如果维度为1,则添加到广播索引列表中

            if char in dimension_dict.keys():
                # For broadcasting cases we always want the largest dim size
                if dimension_dict[char] == 1:
                    dimension_dict[char] = dim
                elif dim not in (1, dimension_dict[char]):
                    raise ValueError("Size of label '%s' for operand %d (%d) "
                                     "does not match previous terms (%d)."
                                     % (char, tnum, dimension_dict[char], dim))
            else:
                dimension_dict[char] = dim
            # 更新维度字典中的值

    # Convert broadcast inds to sets
    broadcast_indices = [set(x) for x in broadcast_indices]
    # 将广播索引转换为集合

    # Compute size of each input array plus the output array
    size_list = [_compute_size_by_dict(term, dimension_dict)
                 for term in input_list + [output_subscript]]
    # 计算每个输入数组及输出数组的大小列表
    max_size = max(size_list)
    # 获取最大大小

    if memory_limit is None:
        memory_arg = max_size
    else:
        memory_arg = memory_limit
    # 设置内存参数

    # Compute naive cost
    # This isn't quite right, need to look into exactly how einsum does this
    inner_product = (sum(len(x) for x in input_sets) - len(indices)) > 0
    # 计算内积
    naive_cost = _flop_count(
        indices, inner_product, len(input_list), dimension_dict
    )
    # 计算天真的成本

    # Compute the path
    if explicit_einsum_path:
        path = path_type[1:]
    elif (
        (path_type is False)
        or (len(input_list) in [1, 2])
        or (indices == output_set)
    ):
        # Nothing to be optimized, leave it to einsum
        path = [tuple(range(len(input_list)))]
    elif path_type == "greedy":
        path = _greedy_path(
            input_sets, output_set, dimension_dict, memory_arg
        )
    # 计算路径的选择逻辑
    elif path_type == "optimal":
        # 如果路径类型是 "optimal",则调用 _optimal_path 函数计算最优路径
        path = _optimal_path(
            input_sets, output_set, dimension_dict, memory_arg
        )
    else:
        # 如果路径类型不是 "optimal",则抛出 KeyError 异常
        raise KeyError("Path name %s not found", path_type)

    # 初始化空列表用于存储成本、缩放、大小和收缩元组
    cost_list, scale_list, size_list, contraction_list = [], [], [], []

    # 构建收缩元组 (位置、gemm、einsum_str、剩余)
    for cnum, contract_inds in enumerate(path):
        # 确保从右到左移除 inds
        contract_inds = tuple(sorted(list(contract_inds), reverse=True))

        # 查找并返回收缩的结果以及相关信息
        contract = _find_contraction(contract_inds, input_sets, output_set)
        out_inds, input_sets, idx_removed, idx_contract = contract

        # 计算 FLOP 数量
        cost = _flop_count(
            idx_contract, idx_removed, len(contract_inds), dimension_dict
        )
        cost_list.append(cost)
        scale_list.append(len(idx_contract))
        size_list.append(_compute_size_by_dict(out_inds, dimension_dict))

        bcast = set()
        tmp_inputs = []
        for x in contract_inds:
            tmp_inputs.append(input_list.pop(x))
            bcast |= broadcast_indices.pop(x)

        new_bcast_inds = bcast - idx_removed

        # 如果有广播操作,不使用 BLAS
        if not len(idx_removed & bcast):
            do_blas = _can_dot(tmp_inputs, out_inds, idx_removed)
        else:
            do_blas = False

        # 最后一个收缩
        if (cnum - len(path)) == -1:
            idx_result = output_subscript
        else:
            sort_result = [(dimension_dict[ind], ind) for ind in out_inds]
            idx_result = "".join([x[1] for x in sorted(sort_result)])

        input_list.append(idx_result)
        broadcast_indices.append(new_bcast_inds)
        einsum_str = ",".join(tmp_inputs) + "->" + idx_result

        # 构建收缩元组并添加到列表中
        contraction = (
            contract_inds, idx_removed, einsum_str, input_list[:], do_blas
        )
        contraction_list.append(contraction)

    # 计算优化成本
    opt_cost = sum(cost_list) + 1

    if len(input_list) != 1:
        # 如果输入列表长度不为1,抛出 RuntimeError 异常
        raise RuntimeError(
            "Invalid einsum_path is specified: {} more operands has to be "
            "contracted.".format(len(input_list) - 1))

    if einsum_call_arg:
        # 如果 einsum_call_arg 为真,返回操作数和收缩列表
        return (operands, contraction_list)

    # 返回路径以及漂亮的字符串表示
    overall_contraction = input_subscripts + "->" + output_subscript
    header = ("scaling", "current", "remaining")

    # 计算速度提升比例和最大大小
    speedup = naive_cost / opt_cost
    max_i = max(size_list)

    # 构建打印路径的字符串
    path_print = "  Complete contraction:  %s\n" % overall_contraction
    path_print += "         Naive scaling:  %d\n" % len(indices)
    path_print += "     Optimized scaling:  %d\n" % max(scale_list)
    path_print += "      Naive FLOP count:  %.3e\n" % naive_cost
    path_print += "  Optimized FLOP count:  %.3e\n" % opt_cost
    # 将理论加速比格式化为字符串,并添加到 path_print 中
    path_print += "   Theoretical speedup:  %3.3f\n" % speedup
    # 将最大中间元素数格式化为科学计数法字符串,并添加到 path_print 中
    path_print += "  Largest intermediate:  %.3e elements\n" % max_i
    # 添加一行分隔线到 path_print 中
    path_print += "-" * 74 + "\n"
    # 使用格式化字符串将表头添加到 path_print 中
    path_print += "%6s %24s %40s\n" % header
    # 添加一行长的分隔线到 path_print 中
    path_print += "-" * 74

    # 遍历收缩列表 contraction_list
    for n, contraction in enumerate(contraction_list):
        # 解包收缩操作的各个部分
        inds, idx_rm, einsum_str, remaining, blas = contraction
        # 构造剩余指标的字符串表示形式,形如 "i,j,k->abc"
        remaining_str = ",".join(remaining) + "->" + output_subscript
        # 构造当前路径的运行信息
        path_run = (scale_list[n], einsum_str, remaining_str)
        # 将当前路径的运行信息格式化并添加到 path_print 中
        path_print += "\n%4d    %24s %40s" % path_run

    # 构造路径列表,并将 'einsum_path' 字符串添加到开头
    path = ['einsum_path'] + path
    # 返回路径列表和打印输出的字符串
    return (path, path_print)
# 定义一个生成器函数 _einsum_dispatcher,用于分派参数
def _einsum_dispatcher(*operands, out=None, optimize=None, **kwargs):
    # 根据注释,此处应该是解释为什么会分派更多参数,参见 _einsum_path_dispatcher 的说明。
    # 生成器函数通过 yield 语句产生操作数及输出对象
    yield from operands
    yield out


# 使用 array_function_dispatch 装饰器将 _einsum_dispatcher 作为分派函数,指定它属于 numpy 模块
@array_function_dispatch(_einsum_dispatcher, module='numpy')
# 定义 einsum 函数,用于处理不同的情况
def einsum(*operands, out=None, optimize=False, **kwargs):
    """
    einsum(subscripts, *operands, out=None, dtype=None, order='K',
           casting='safe', optimize=False)

    根据爱因斯坦求和约定在操作数上执行求和。

    使用爱因斯坦求和约定,许多常见的多维线性代数数组操作可以用简单的方式表示。
    在 *implicit* 模式下,`einsum` 计算这些值。

    在 *explicit* 模式下,`einsum` 提供了更多的灵活性,可以计算其他可能不是经典爱因斯坦求和操作的数组操作,
    通过禁用或强制求和指定的下标标签。

    请参阅注释和示例以获取更多说明。

    Parameters
    ----------
    subscripts : str
        指定求和下标的字符串,以逗号分隔的下标标签列表。除非明确指定输出形式,否则将执行隐式(经典爱因斯坦求和)计算。
    operands : list of array_like
        这些是操作的数组。
    out : ndarray, optional
        如果提供,则将计算结果存入此数组。
    dtype : {data-type, None}, optional
        如果提供,则强制使用指定的数据类型进行计算。
        请注意,可能需要更宽松的 `casting` 参数来允许转换。默认为 None。
    order : {'C', 'F', 'A', 'K'}, optional
        控制输出的内存布局。'C' 表示应为 C 连续,'F' 表示应为 Fortran 连续,
        'A' 表示如果输入全部为 'F',则输出也应为 'F',否则为 'C''K' 表示应尽可能接近输入的布局,包括任意排列的轴。
        默认为 'K'。
    casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
        控制可能发生的数据转换类型。不推荐设置为 'unsafe',因为可能会对累积产生不利影响。

        * 'no' 表示根本不应进行数据类型转换。
        * 'equiv' 表示只允许字节顺序的改变。
        * 'safe' 表示只允许可以保留值的转换。
        * 'same_kind' 表示只允许安全转换或同一种类内的转换,例如 float64 到 float32。
        * 'unsafe' 表示可以进行任何数据转换。

        默认为 'safe'。
    optimize : bool, optional
        是否应该优化 einsum 路径。默认为 False"""
    # 函数文档字符串提供了 einsum 函数的详细说明,包括它的参数和使用方法。
    # 函数本身实现了根据爱因斯坦求和约定执行多维数组操作的功能。
    pass  # 函数体暂未提供,实际实现中会根据 subscripts 和 operands 执行相应的计算
    optimize : {False, True, 'greedy', 'optimal'}, optional
        # 控制是否进行中间优化。如果为False,则不进行优化;如果为True,默认使用'greedy'算法。
        # 也可以接受来自np.einsum_path函数的显式缩并列表。详见np.einsum_path获取更多信息。默认为False。

    Returns
    -------
    output : ndarray
        # 基于爱因斯坦求和约定进行的计算结果。

    See Also
    --------
    einsum_path, dot, inner, outer, tensordot, linalg.multi_dot
    einsum:
        # `einsum`函数提供了一种简洁的方式来表示多维线性代数数组操作。

    Notes
    -----
    .. versionadded:: 1.6.0

    The Einstein summation convention can be used to compute
    many multi-dimensional, linear algebraic array operations. `einsum`
    provides a succinct way of representing these.
    # 爱因斯坦求和约定可用于计算许多多维线性代数数组操作。`einsum`提供了一种简洁的表示方式。

    A non-exhaustive list of these operations,
    which can be computed by `einsum`, is shown below along with examples:
    # 下面列出了一些可通过`einsum`计算的操作,以及相应的示例:

    * Trace of an array, :py:func:`numpy.trace`.
    * Return a diagonal, :py:func:`numpy.diag`.
    * Array axis summations, :py:func:`numpy.sum`.
    * Transpositions and permutations, :py:func:`numpy.transpose`.
    * Matrix multiplication and dot product, :py:func:`numpy.matmul`
        :py:func:`numpy.dot`.
    * Vector inner and outer products, :py:func:`numpy.inner`
        :py:func:`numpy.outer`.
    * Broadcasting, element-wise and scalar multiplication,
        :py:func:`numpy.multiply`.
    * Tensor contractions, :py:func:`numpy.tensordot`.
    * Chained array operations, in efficient calculation order,
        :py:func:`numpy.einsum_path`.
    # 列出了一些可以通过`einsum`计算的操作,以及相应的示例,包括数组的迹、对角线、轴的求和、转置、矩阵乘法、向量内积外积、广播、张量收缩以及连锁数组操作。

    The subscripts string is a comma-separated list of subscript labels,
    where each label refers to a dimension of the corresponding operand.
    # 子脚本字符串是逗号分隔的子脚本标签列表,其中每个标签都引用相应操作数的一个维度。

    In *implicit mode*, the chosen subscripts are important
    since the axes of the output are reordered alphabetically.  This
    means that ``np.einsum('ij', a)`` doesn't affect a 2D array, while
    # 在隐式模式下,所选择的子脚本很重要,因为输出的轴会按字母顺序重新排序。
    # 这意味着`np.einsum('ij', a)`不会影响一个2D数组,
    # 使用 `np.einsum` 函数可以根据爱因斯坦求和约定计算张量的乘积、对角线元素、轴上的和等操作。
    
    # 当操作符只有一个时,不会进行轴上的求和,也不会返回输出参数,而是返回操作数的视图。
    
    # `einsum` 还提供了另一种方式来提供子脚本和操作数,即 `einsum(op0, sublist0, op1, sublist1, ..., [sublistout])`。如果在这种格式中没有提供输出形状,`einsum` 将以隐式模式计算,否则将显式执行。
    
    # 从版本 1.10.0 开始,`einsum` 返回的视图现在在输入数组可写时也是可写的。
    
    # 版本 1.12.0 中新增了 `optimize` 参数,它可以优化 `einsum` 表达式的收缩顺序。对于三个或更多操作数的收缩,这可以大幅提高计算效率,但在计算过程中会增加内存占用。
    Typically a 'greedy' algorithm is applied which empirical tests have shown
    returns the optimal path in the majority of cases. In some cases 'optimal'
    will return the superlative path through a more expensive, exhaustive
    search. For iterative calculations it may be advisable to calculate
    the optimal path once and reuse that path by supplying it as an argument.
    An example is given below.

    See :py:func:`numpy.einsum_path` for more details.


    # 通常使用“贪婪”算法,经验测试表明在大多数情况下返回最优路径。在某些情况下,“optimal”
    # 会通过更昂贵、详尽的搜索返回卓越路径。对于迭代计算,建议计算一次最优路径并通过参数重复使用该路径。
    # 下面给出一个示例。
    
    # 查看更多详细信息,请参阅 :py:func:`numpy.einsum_path`。


```py    
    Examples
    --------
    >>> a = np.arange(25).reshape(5,5)
    >>> b = np.arange(5)
    >>> c = np.arange(6).reshape(2,3)

    Trace of a matrix:


    # 创建示例数组
    a = np.arange(25).reshape(5,5)
    b = np.arange(5)
    c = np.arange(6).reshape(2,3)

    # 计算矩阵的迹



    >>> np.einsum('ii', a)
    60
    >>> np.einsum(a, [0,0])
    60
    >>> np.trace(a)
    60


    # 使用einsum计算矩阵对角线元素之和
    >>> np.einsum('ii', a)
    60
    >>> np.einsum(a, [0,0])
    60
    >>> np.trace(a)
    60



    Extract the diagonal (requires explicit form):


    # 提取对角线元素(需要显式形式)



    >>> np.einsum('ii->i', a)
    array([ 0,  6, 12, 18, 24])
    >>> np.einsum(a, [0,0], [0])
    array([ 0,  6, 12, 18, 24])
    >>> np.diag(a)
    array([ 0,  6, 12, 18, 24])


    # 使用einsum提取对角线元素到一维数组
    >>> np.einsum('ii->i', a)
    array([ 0,  6, 12, 18, 24])
    >>> np.einsum(a, [0,0], [0])
    array([ 0,  6, 12, 18, 24])
    >>> np.diag(a)
    array([ 0,  6, 12, 18, 24])



    Sum over an axis (requires explicit form):


    # 沿着指定轴求和(需要显式形式)



    >>> np.einsum('ij->i', a)
    array([ 10,  35,  60,  85, 110])
    >>> np.einsum(a, [0,1], [0])
    array([ 10,  35,  60,  85, 110])
    >>> np.sum(a, axis=1)
    array([ 10,  35,  60,  85, 110])


    # 使用einsum沿着行求和并返回结果数组
    >>> np.einsum('ij->i', a)
    array([ 10,  35,  60,  85, 110])
    >>> np.einsum(a, [0,1], [0])
    array([ 10,  35,  60,  85, 110])
    >>> np.sum(a, axis=1)
    array([ 10,  35,  60,  85, 110])



    For higher dimensional arrays summing a single axis can be done
    with ellipsis:


    # 对于更高维度的数组,可以使用省略号来沿着单个轴求和



    >>> np.einsum('...j->...', a)
    array([ 10,  35,  60,  85, 110])
    >>> np.einsum(a, [Ellipsis,1], [Ellipsis])
    array([ 10,  35,  60,  85, 110])


    # 使用einsum沿着列(最后一个轴)求和并返回结果数组
    >>> np.einsum('...j->...', a)
    array([ 10,  35,  60,  85, 110])
    >>> np.einsum(a, [Ellipsis,1], [Ellipsis])
    array([ 10,  35,  60,  85, 110])



    Compute a matrix transpose, or reorder any number of axes:


    # 计算矩阵转置或重新排列任意数量的轴



    >>> np.einsum('ji', c)
    array([[0, 3],
           [1, 4],
           [2, 5]])
    >>> np.einsum('ij->ji', c)
    array([[0, 3],
           [1, 4],
           [2, 5]])
    >>> np.einsum(c, [1,0])
    array([[0, 3],
           [1, 4],
           [2, 5]])
    >>> np.transpose(c)
    array([[0, 3],
           [1, 4],
           [2, 5]])


    # 使用einsum计算矩阵转置或重排轴的操作及结果
    >>> np.einsum('ji', c)
    array([[0, 3],
           [1, 4],
           [2, 5]])
    >>> np.einsum('ij->ji', c)
    array([[0, 3],
           [1, 4],
           [2, 5]])
    >>> np.einsum(c, [1,0])
    array([[0, 3],
           [1, 4],
           [2, 5]])
    >>> np.transpose(c)
    array([[0, 3],
           [1, 4],
           [2, 5]])



    Vector inner products:


    # 向量的内积运算



    >>> np.einsum('i,i', b, b)
    30
    >>> np.einsum(b, [0], b, [0])
    30
    >>> np.inner(b,b)
    30


    # 使用einsum计算向量的内积并返回结果
    >>> np.einsum('i,i', b, b)
    30
    >>> np.einsum(b, [0], b, [0])
    30
    >>> np.inner(b,b)
    30



    Matrix vector multiplication:


    # 矩阵与向量的乘法运算



    >>> np.einsum('ij,j', a, b)
    array([ 30,  80, 130, 180, 230])
    >>> np.einsum(a, [0,1], b, [1])
    array([ 30,  80, 130, 180, 230])
    >>> np.dot(a, b)
    array([ 30,  80, 130, 180, 230])
    >>> np.einsum('...j,j', a, b)
    array([ 30,  80, 130, 180, 230])


    # 使用einsum计算矩阵与向量的乘积并返回结果数组
    >>> np.einsum('ij,j', a, b)
    array([ 30,  80, 130, 180, 230])
    >>> np.einsum(a, [0,1], b, [1])
    array([ 30,  80, 130, 180, 230])
    >>> np.dot(a, b)
    array([ 30,  80, 130, 180, 230])
    >>> np.einsum('...j,j', a, b)
    array([ 30,  80, 130, 180, 230])



    Broadcasting and
    # 如果指定了输出(out),则特殊处理
    specified_out = out is not None
    
    # 如果不进行优化,使用纯粹的 einsum 运算
    if optimize is False:
        # 如果指定了输出,将其设为关键字参数中的输出
        if specified_out:
            kwargs['out'] = out
        # 返回通过 c_einsum 函数计算得到的结果,使用给定的操作数和关键字参数
        return c_einsum(*operands, **kwargs)
    
    # 检查关键字参数,避免在稍后出现更难理解的错误,同时不必在此处重复默认值
    valid_einsum_kwargs = ['dtype', 'order', 'casting']
    # 检查是否存在未知的关键字参数
    unknown_kwargs = [k for (k, v) in kwargs.items() if
                      k not in valid_einsum_kwargs]
    # 如果存在未知参数,抛出类型错误异常
    if len(unknown_kwargs):
        raise TypeError("Did not understand the following kwargs: %s"
                        % unknown_kwargs)

    # 构建收缩列表和操作数
    operands, contraction_list = einsum_path(*operands, optimize=optimize,
                                             einsum_call=True)

    # 处理输出数组的顺序关键字参数
    output_order = kwargs.pop('order', 'K')
    # 如果输出顺序是 'A',并且所有操作数都是 F 连续的,则设定输出顺序为 'F';否则设定为 'C'
    if output_order.upper() == 'A':
        if all(arr.flags.f_contiguous for arr in operands):
            output_order = 'F'
        else:
            output_order = 'C'

    # 开始收缩循环
    for num, contraction in enumerate(contraction_list):
        inds, idx_rm, einsum_str, remaining, blas = contraction
        tmp_operands = [operands.pop(x) for x in inds]

        # 是否需要处理输出?
        handle_out = specified_out and ((num + 1) == len(contraction_list))

        # 如果是 BLAS 收缩
        if blas:
            # 已经处理过检查
            input_str, results_index = einsum_str.split('->')
            input_left, input_right = input_str.split(',')

            # 构建收缩后的结果张量
            tensor_result = input_left + input_right
            for s in idx_rm:
                tensor_result = tensor_result.replace(s, "")

            # 查找需要收缩的索引位置
            left_pos, right_pos = [], []
            for s in sorted(idx_rm):
                left_pos.append(input_left.find(s))
                right_pos.append(input_right.find(s))

            # 执行张量收缩
            new_view = tensordot(
                *tmp_operands, axes=(tuple(left_pos), tuple(right_pos))
            )

            # 如果需要构建新视图或者处理输出,调用 c_einsum 函数
            if (tensor_result != results_index) or handle_out:
                if handle_out:
                    kwargs["out"] = out
                new_view = c_einsum(
                    tensor_result + '->' + results_index, new_view, **kwargs
                )

        # 如果不是 BLAS 收缩,调用 einsum 函数
        else:
            # 如果指定了输出参数 out
            if handle_out:
                kwargs["out"] = out

            # 执行收缩操作
            new_view = c_einsum(einsum_str, *tmp_operands, **kwargs)

        # 将新视图添加到操作数列表中,并删除临时操作数和新视图引用
        operands.append(new_view)
        del tmp_operands, new_view

    # 如果指定了输出 out,返回 out;否则将第一个操作数转换为数组并返回,按指定的顺序
    if specified_out:
        return out
    else:
        return asanyarray(operands[0], order=output_order)

.\numpy\numpy\_core\einsumfunc.pyi

from collections.abc import Sequence
from typing import TypeVar, Any, overload, Literal

import numpy as np
from numpy import number, _OrderKACF
from numpy._typing import (
    NDArray,
    _ArrayLikeBool_co,
    _ArrayLikeUInt_co,
    _ArrayLikeInt_co,
    _ArrayLikeFloat_co,
    _ArrayLikeComplex_co,
    _ArrayLikeObject_co,
    _DTypeLikeBool,
    _DTypeLikeUInt,
    _DTypeLikeInt,
    _DTypeLikeFloat,
    _DTypeLikeComplex,
    _DTypeLikeComplex_co,
    _DTypeLikeObject,
)

_ArrayType = TypeVar(
    "_ArrayType",
    bound=NDArray[np.bool | number[Any]],
)

_OptimizeKind = None | bool | Literal["greedy", "optimal"] | Sequence[Any]
_CastingSafe = Literal["no", "equiv", "safe", "same_kind"]
_CastingUnsafe = Literal["unsafe"]

__all__: list[str]

# TODO: Properly handle the `casting`-based combinatorics
# TODO: We need to evaluate the content `__subscripts` in order
# to identify whether or an array or scalar is returned. At a cursory
# glance this seems like something that can quite easily be done with
# a mypy plugin.
# Something like `is_scalar = bool(__subscripts.partition("->")[-1])`

@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeBool_co,
    out: None = ...,
    dtype: None | _DTypeLikeBool = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeUInt_co,
    out: None = ...,
    dtype: None | _DTypeLikeUInt = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeInt_co,
    out: None = ...,
    dtype: None | _DTypeLikeInt = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeFloat_co,
    out: None = ...,
    dtype: None | _DTypeLikeFloat = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeComplex_co,
    out: None = ...,
    dtype: None | _DTypeLikeComplex = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: Any,
    casting: _CastingUnsafe,
    dtype: None | _DTypeLikeComplex_co = ...,
    out: None = ...,
    order: _OrderKACF = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeComplex_co,
    out: _ArrayType,
    dtype: None | _DTypeLikeComplex_co = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...


注释:

# 导入必要的模块和类型声明
from collections.abc import Sequence
from typing import TypeVar, Any, overload, Literal

import numpy as np
from numpy import number, _OrderKACF
from numpy._typing import (
    NDArray,
    _ArrayLikeBool_co,
    _ArrayLikeUInt_co,
    _ArrayLikeInt_co,
    _ArrayLikeFloat_co,
    _ArrayLikeComplex_co,
    _ArrayLikeObject_co,
    _DTypeLikeBool,
    _DTypeLikeUInt,
    _DTypeLikeInt,
    _DTypeLikeFloat,
    _DTypeLikeComplex,
    _DTypeLikeComplex_co,
    _DTypeLikeObject,
)

# 定义类型变量
_ArrayType = TypeVar(
    "_ArrayType",
    bound=NDArray[np.bool | number[Any]],
)

# 定义类型别名
_OptimizeKind = None | bool | Literal["greedy", "optimal"] | Sequence[Any]
_CastingSafe = Literal["no", "equiv", "safe", "same_kind"]
_CastingUnsafe = Literal["unsafe"]

# 声明 __all__ 列表
__all__: list[str]

# TODO: Properly handle the `casting`-based combinatorics
# TODO: We need to evaluate the content `__subscripts` in order
# to identify whether or an array or scalar is returned. At a cursory
# glance this seems like something that can quite easily be done with
# a mypy plugin.
# Something like `is_scalar = bool(__subscripts.partition("->")[-1])`

# 函数重载定义,根据不同的输入类型签名处理 `einsum` 函数
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeBool_co,
    out: None = ...,
    dtype: None | _DTypeLikeBool = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeUInt_co,
    out: None = ...,
    dtype: None | _DTypeLikeUInt = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeInt_co,
    out: None = ...,
    dtype: None | _DTypeLikeInt = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeFloat_co,
    out: None = ...,
    dtype: None | _DTypeLikeFloat = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeComplex_co,
    out: None = ...,
    dtype: None | _DTypeLikeComplex = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: Any,
    casting: _CastingUnsafe,
    dtype: None | _DTypeLikeComplex_co = ...,
    out: None = ...,
    order: _OrderKACF = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeComplex_co,
    out: _ArrayType,
    dtype: None | _DTypeLikeComplex_co = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any:
    ...
    optimize: _OptimizeKind = ...,


    # 定义一个名为 optimize 的变量,类型为 _OptimizeKind,初始值为省略号(未指定具体值)
# NOTE: `einsum` function with an overload taking specific arguments and returning `_ArrayType`.
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: Any,
    out: _ArrayType,
    casting: _CastingUnsafe,
    dtype: None | _DTypeLikeComplex_co = ...,
    order: _OrderKACF = ...,
    optimize: _OptimizeKind = ...,
) -> _ArrayType: ...

# NOTE: `einsum` function with an overload taking `_ArrayLikeObject_co` operands and returning `Any`.
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeObject_co,
    out: None = ...,
    dtype: None | _DTypeLikeObject = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> Any: ...

# NOTE: `einsum` function with an overload taking specific arguments and returning `Any`.
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: Any,
    casting: _CastingUnsafe,
    dtype: None | _DTypeLikeObject = ...,
    out: None = ...,
    order: _OrderKACF = ...,
    optimize: _OptimizeKind = ...,
) -> Any: ...

# NOTE: `einsum` function with an overload taking `_ArrayLikeObject_co` operands and returning `_ArrayType`.
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeObject_co,
    out: _ArrayType,
    dtype: None | _DTypeLikeObject = ...,
    order: _OrderKACF = ...,
    casting: _CastingSafe = ...,
    optimize: _OptimizeKind = ...,
) -> _ArrayType: ...

# NOTE: `einsum` function with an overload taking specific arguments and returning `_ArrayType`.
@overload
def einsum(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: Any,
    out: _ArrayType,
    casting: _CastingUnsafe,
    dtype: None | _DTypeLikeObject = ...,
    order: _OrderKACF = ...,
    optimize: _OptimizeKind = ...,
) -> _ArrayType: ...

# NOTE: `einsum_path` function calculates and returns the optimal path for `einsum`.
# The function takes subscripts and operands, where operands are either complex arrays or object types.
# The `optimize` parameter controls optimization behavior.
def einsum_path(
    subscripts: str | _ArrayLikeInt_co,
    /,
    *operands: _ArrayLikeComplex_co | _DTypeLikeObject,
    optimize: _OptimizeKind = ...,
) -> tuple[list[Any], str]: ...

.\numpy\numpy\_core\feature_detection_misc.h

# 包含标准库 <stddef.h>,用于提供 size_t 类型的定义
#include <stddef.h>

# 声明函数 backtrace,返回类型为 int,接受两个参数:指向指针数组的指针和整数类型的参数
int backtrace(void **, int);

# 声明函数 madvise,返回类型为 int,接受三个参数:指向内存区域的指针、区域大小的 size_t 类型参数和一个整数类型参数
int madvise(void *, size_t, int);

.\numpy\numpy\_core\feature_detection_stdio.h

#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>


注释:


// 定义 _GNU_SOURCE 宏,用于启用 GNU 扩展特性
#define _GNU_SOURCE
// 包含标准输入输出库的头文件
#include <stdio.h>
// 包含文件控制相关的头文件,例如 open 函数
#include <fcntl.h>


这段代码是一个C语言的预处理器指令,用于在编译时修改代码。`#define _GNU_SOURCE` 指令定义了 `_GNU_SOURCE` 宏,该宏启用了GNU的扩展特性,可以使得一些额外的GNU函数和特性在标准库中可用。

`#include <stdio.h>` 和 `#include <fcntl.h>` 是包含标准输入输出库和文件控制相关的头文件,分别提供了处理标准输入输出和文件操作的函数和宏定义,如 `open()` 函数就在 `<fcntl.h>` 中定义。

这段代码本身没有执行语句,仅仅是预处理阶段的指令,作用是为了确保在后续的代码中能够使用所需的特性和函数定义。

.\numpy\numpy\_core\fromnumeric.py

"""
Module containing non-deprecated functions borrowed from Numeric.

"""
# 引入必要的模块和库
import functools  # 提供函数式编程的工具
import types  # 提供类型检查和操作类型的工具
import warnings  # 提供警告处理相关的功能

import numpy as np  # 引入 NumPy 库,并使用 np 别名
from .._utils import set_module  # 从上级模块中引入 set_module 函数
from . import multiarray as mu  # 从当前包中引入 multiarray 模块,并使用 mu 别名
from . import overrides  # 从当前包中引入 overrides 模块
from . import umath as um  # 从当前包中引入 umath 模块,并使用 um 别名
from . import numerictypes as nt  # 从当前包中引入 numerictypes 模块,并使用 nt 别名
from .multiarray import asarray, array, asanyarray, concatenate  # 从 multiarray 模块中引入特定函数
from ._multiarray_umath import _array_converter  # 从 _multiarray_umath 模块中引入 _array_converter 函数
from . import _methods  # 从当前包中引入 _methods 模块

_dt_ = nt.sctype2char  # 将 sctype2char 函数结果赋值给 _dt_

# functions that are methods
# 定义一个列表,包含当前模块中可供外部使用的函数名
__all__ = [
    'all', 'amax', 'amin', 'any', 'argmax',
    'argmin', 'argpartition', 'argsort', 'around', 'choose', 'clip',
    'compress', 'cumprod', 'cumsum', 'diagonal', 'mean',
    'max', 'min', 'matrix_transpose',
    'ndim', 'nonzero', 'partition', 'prod', 'ptp', 'put',
    'ravel', 'repeat', 'reshape', 'resize', 'round',
    'searchsorted', 'shape', 'size', 'sort', 'squeeze',
    'std', 'sum', 'swapaxes', 'take', 'trace', 'transpose', 'var',
]

_gentype = types.GeneratorType  # 将 GeneratorType 类型赋值给 _gentype
# save away Python sum
_sum_ = sum  # 将内置的 sum 函数保存到 _sum_

# 定义一个偏函数 array_function_dispatch,使用 overrides 模块中的 array_function_dispatch 函数,并指定 module='numpy'
array_function_dispatch = functools.partial(
    overrides.array_function_dispatch, module='numpy')


# functions that are now methods

# 定义一个函数 _wrapit,接受一个对象 obj、一个方法 method,以及其他参数
def _wrapit(obj, method, *args, **kwds):
    conv = _array_converter(obj)  # 调用 _array_converter 函数将 obj 转换为数组
    # 获取数组对象 arr,并调用其 method 方法,传入 args 和 kwds 参数
    arr, = conv.as_arrays(subok=False)
    result = getattr(arr, method)(*args, **kwds)  # 调用 arr 对象的 method 方法,并传入 args 和 kwds 参数

    return conv.wrap(result, to_scalar=False)  # 将结果 wrap 起来,并返回


# 定义一个函数 _wrapfunc,接受一个对象 obj、一个方法 method,以及其他参数
def _wrapfunc(obj, method, *args, **kwds):
    bound = getattr(obj, method, None)  # 尝试从 obj 中获取名为 method 的方法,并赋值给 bound
    if bound is None:
        return _wrapit(obj, method, *args, **kwds)  # 如果 bound 为 None,则调用 _wrapit 函数处理

    try:
        return bound(*args, **kwds)  # 尝试调用 bound 方法,传入 args 和 kwds 参数
    except TypeError:
        # 处理 TypeError 异常,通常出现在对象的类中有该方法,但其签名与 NumPy 的不同的情况下
        # 在 except 子句中调用 _wrapit 函数,确保异常链中包含 traceback
        return _wrapit(obj, method, *args, **kwds)


# 定义一个函数 _wrapreduction,接受一个对象 obj、一个 ufunc、一个方法 method,以及其他参数
def _wrapreduction(obj, ufunc, method, axis, dtype, out, **kwargs):
    passkwargs = {k: v for k, v in kwargs.items()
                  if v is not np._NoValue}  # 创建 passkwargs 字典,筛选出值不是 np._NoValue 的键值对

    if type(obj) is not mu.ndarray:  # 如果 obj 的类型不是 mu.ndarray
        try:
            reduction = getattr(obj, method)  # 尝试从 obj 中获取名为 method 的属性,并赋值给 reduction
        except AttributeError:
            pass
        else:
            # 这个分支用于像 any 这样不支持 dtype 参数的归约操作
            if dtype is not None:
                return reduction(axis=axis, dtype=dtype, out=out, **passkwargs)  # 调用 reduction 方法,传入特定参数
            else:
                return reduction(axis=axis, out=out, **passkwargs)  # 调用 reduction 方法,传入特定参数

    return ufunc.reduce(obj, axis, dtype, out, **passkwargs)  # 调用 ufunc 的 reduce 方法,传入特定参数


# 定义一个函数 _wrapreduction_any_all,接受一个对象 obj、一个 ufunc、一个方法 method,以及其他参数
def _wrapreduction_any_all(obj, ufunc, method, axis, out, **kwargs):
    # 与上面的函数相同,但是 dtype 参数始终为 bool 类型(但不会传递)
    # 创建一个字典 passkwargs,其中包含所有非 numpy._NoValue 值的关键字参数
    passkwargs = {k: v for k, v in kwargs.items()
                  if v is not np._NoValue}
    
    # 检查 obj 对象的类型是否不是 mu.ndarray(即不是 numpy.ndarray 类型)
    if type(obj) is not mu.ndarray:
        # 尝试从 obj 对象中获取指定方法(method)的归约函数
        try:
            reduction = getattr(obj, method)
        # 如果 obj 对象中没有该方法(AttributeError 异常)
        except AttributeError:
            pass  # 如果出现异常则什么都不做
        else:
            # 如果成功获取到方法,则调用该方法进行归约操作,传递给该方法的参数为 axis, out, 和 passkwargs 字典
            return reduction(axis=axis, out=out, **passkwargs)
    
    # 如果 obj 是 numpy.ndarray 类型,则使用 ufunc.reduce 方法进行归约操作
    return ufunc.reduce(obj, axis, bool, out, **passkwargs)
# 定义一个简单的分发函数,返回传入的参数 a 和 out
def _take_dispatcher(a, indices, axis=None, out=None, mode=None):
    return (a, out)

# 使用 array_function_dispatch 装饰器将 take 函数与 _take_dispatcher 分发函数关联起来
@array_function_dispatch(_take_dispatcher)
def take(a, indices, axis=None, out=None, mode='raise'):
    """
    Take elements from an array along an axis.

    When axis is not None, this function does the same thing as "fancy"
    indexing (indexing arrays using arrays); however, it can be easier to use
    if you need elements along a given axis. A call such as
    ``np.take(arr, indices, axis=3)`` is equivalent to
    ``arr[:,:,:,indices,...]``.

    Explained without fancy indexing, this is equivalent to the following use
    of `ndindex`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of
    indices::

        Ni, Nk = a.shape[:axis], a.shape[axis+1:]
        Nj = indices.shape
        for ii in ndindex(Ni):
            for jj in ndindex(Nj):
                for kk in ndindex(Nk):
                    out[ii + jj + kk] = a[ii + (indices[jj],) + kk]

    Parameters
    ----------
    a : array_like (Ni..., M, Nk...)
        The source array.
    indices : array_like (Nj...)
        The indices of the values to extract.

        .. versionadded:: 1.8.0

        Also allow scalars for indices.
    axis : int, optional
        The axis over which to select values. By default, the flattened
        input array is used.
    out : ndarray, optional (Ni..., Nj..., Nk...)
        If provided, the result will be placed in this array. It should
        be of the appropriate shape and dtype. Note that `out` is always
        buffered if `mode='raise'`; use other modes for better performance.
    mode : {'raise', 'wrap', 'clip'}, optional
        Specifies how out-of-bounds indices will behave.

        * 'raise' -- raise an error (default)
        * 'wrap' -- wrap around
        * 'clip' -- clip to the range

        'clip' mode means that all indices that are too large are replaced
        by the index that addresses the last element along that axis. Note
        that this disables indexing with negative numbers.

    Returns
    -------
    out : ndarray (Ni..., Nj..., Nk...)
        The returned array has the same type as `a`.

    See Also
    --------
    compress : Take elements using a boolean mask
    ndarray.take : equivalent method
    take_along_axis : Take elements by matching the array and the index arrays

    Notes
    -----

    By eliminating the inner loop in the description above, and using `s_` to
    build simple slice objects, `take` can be expressed  in terms of applying
    fancy indexing to each 1-d slice::

        Ni, Nk = a.shape[:axis], a.shape[axis+1:]
        for ii in ndindex(Ni):
            for kk in ndindex(Nj):
                out[ii + s_[...,] + kk] = a[ii + s_[:,] + kk][indices]

    For this reason, it is equivalent to (but faster than) the following use
    of `apply_along_axis`::

        out = np.apply_along_axis(lambda a_1d: a_1d[indices], axis, a)

    Examples
    --------
    >>> a = [4, 3, 5, 7, 6, 8]
    """
    # 创建一个包含索引的列表
    indices = [0, 1, 4]
    # 使用 `np.take` 函数从数组 `a` 中按照给定的索引取值,并返回一个新的数组
    # 结果是从 `a` 中取出索引为 0, 1, 4 的元素,组成的一维数组
    >>> np.take(a, indices)
    array([4, 3, 6])

    # 如果 `a` 是一个 ndarray,可以使用 "fancy" 索引。
    # 将 `a` 转换为 ndarray 类型
    >>> a = np.array(a)
    # 使用索引数组 `indices` 从 `a` 中获取元素,返回一个新的数组
    # 结果同上,从 `a` 中取出索引为 0, 1, 4 的元素,组成的一维数组
    >>> a[indices]
    array([4, 3, 6])

    # 如果 `indices` 不是一维的,输出的数组也会有相应的维度
    >>> np.take(a, [[0, 1], [2, 3]])
    array([[4, 3],
           [5, 7]])
    """
    # 调用 `_wrapfunc` 函数,对数组 `a` 进行 `take` 操作,返回结果
    return _wrapfunc(a, 'take', indices, axis=axis, out=out, mode=mode)
# 定义一个函数 _reshape_dispatcher,用于分发参数至 reshape 函数
def _reshape_dispatcher(a, /, shape=None, *, newshape=None, order=None, copy=None):
    # 返回参数 a 的元组形式
    return (a,)

# 使用 array_function_dispatch 装饰器,将 _reshape_dispatcher 函数与 reshape 函数关联起来
@array_function_dispatch(_reshape_dispatcher)
# 定义 reshape 函数,用于改变数组的形状而不修改其数据
def reshape(a, /, shape=None, *, newshape=None, order='C', copy=None):
    """
    给数组重新定义形状,但不改变其数据。

    Parameters
    ----------
    a : array_like
        待重新形状的数组。
    shape : intint 元组
        新的形状应该与原始形状兼容。如果是整数,则结果将是该长度的一维数组。
        形状的一个维度可以是 -1。在这种情况下,值将从数组的长度和剩余维度中推断出来。
    newshape : intint 元组
        .. 已弃用:: 2.1
            已由 ``shape`` 参数取代。保留向后兼容性。
    order : {'C', 'F', 'A'}, 可选
        使用此索引顺序读取 ``a`` 的元素,并使用此索引顺序将元素放入重新形状的数组中。
        'C' 表示使用类似 C 的索引顺序读取/写入元素,最后一个轴索引最快变化,第一个轴索引最慢变化。
        'F' 表示使用类似 Fortran 的索引顺序读取/写入元素,第一个索引最快变化,最后一个索引最慢变化。
        注意,'C''F' 选项不考虑底层数组的内存布局,仅指索引顺序。
        'A' 表示如果 ``a`` 在内存中是 Fortran 连续的,则以类似 Fortran 的索引顺序读取/写入元素,否则以 C 的顺序。
    copy : bool, 可选
        如果为 ``True``,则复制数组数据。如果为 ``None``,只有在 ``order`` 所需时才会进行复制。
        对于 ``False``,如果无法避免复制,则会引发 ``ValueError``。默认值: ``None``。

    Returns
    -------
    reshaped_array : ndarray
        如果可能,这将是一个新的视图对象;否则,它将是一个副本。请注意,无法保证返回数组的内存布局(C 或 Fortran 连续性)。

    See Also
    --------
    ndarray.reshape : 等效的方法。

    Notes
    -----
    不总是能够在不复制数据的情况下改变数组的形状。

    ``order`` 关键字同时指定了从 ``a`` 中 *获取* 值的索引顺序,以及将值 *放置* 到输出数组中的索引顺序。
    例如,假设你有一个数组:

    >>> a = np.arange(6).reshape((3, 2))
    >>> a
    array([[0, 1],
           [2, 3],
           [4, 5]])

    可以将重新形状视为首先拉平数组(使用给定的索引顺序),然后将拉平数组中的元素按照相同的索引顺序插入到新数组中。

    >>> np.reshape(a, (2, 3)) # 使用类似 C 的索引顺序
    array([[0, 1, 2],
           [3, 4, 5]])
    >>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape
    # 将数组展平(按行展平),然后按指定形状重新排列,结果与原始数组相同
    array([[0, 1, 2],
           [3, 4, 5]])
    >>> np.reshape(a, (2, 3), order='F') # Fortran-like index ordering
    # 按照 Fortran 风格的索引顺序重新排列数组
    array([[0, 4, 3],
           [2, 1, 5]])
    >>> np.reshape(np.ravel(a, order='F'), (2, 3), order='F')
    # 先按 Fortran 风格展平数组,然后按照同样的顺序重新排列成指定形状
    array([[0, 4, 3],
           [2, 1, 5]])

    Examples
    --------
    >>> a = np.array([[1,2,3], [4,5,6]])
    >>> np.reshape(a, 6)
    # 将数组展平为一维数组
    array([1, 2, 3, 4, 5, 6])
    >>> np.reshape(a, 6, order='F')
    # 按 Fortran 风格将数组展平为一维数组
    array([1, 4, 2, 5, 3, 6])

    >>> np.reshape(a, (3,-1))       # the unspecified value is inferred to be 2
    # 将数组按照指定形状重新排列,其中 -1 表示自动推断维度大小
    array([[1, 2],
           [3, 4],
           [5, 6]])
    """
    if newshape is None and shape is None:
        # 如果没有指定 newshape 和 shape 参数,则抛出 TypeError
        raise TypeError(
            "reshape() missing 1 required positional argument: 'shape'")
    if newshape is not None:
        if shape is not None:
            # 如果同时指定了 newshape 和 shape 参数,则抛出 TypeError
            raise TypeError(
                "You cannot specify 'newshape' and 'shape' arguments "
                "at the same time.")
        # 在 NumPy 2.1 版本中已弃用,2024-04-18
        # 发出警告,建议使用 shape=... 或者直接传递形状参数
        warnings.warn(
            "`newshape` keyword argument is deprecated, "
            "use `shape=...` or pass shape positionally instead. "
            "(deprecated in NumPy 2.1)",
            DeprecationWarning,
            stacklevel=2,
        )
        shape = newshape
    if copy is not None:
        # 如果指定了 copy 参数,则使用 _wrapfunc 函数进行操作
        return _wrapfunc(a, 'reshape', shape, order=order, copy=copy)
    # 否则直接使用 _wrapfunc 函数进行操作
    return _wrapfunc(a, 'reshape', shape, order=order)
# 定义一个生成器函数 _choose_dispatcher,用于生成参数 a、choices 和 out 的值
def _choose_dispatcher(a, choices, out=None, mode=None):
    # 返回生成器对象,依次生成 a、choices 中的元素以及 out
    yield a
    yield from choices
    yield out

# 用装饰器 array_function_dispatch 将 _choose_dispatcher 与 choose 函数关联起来
@array_function_dispatch(_choose_dispatcher)
# 定义函数 choose,用于从索引数组和选择数组中构造数组
def choose(a, choices, out=None, mode='raise'):
    """
    Construct an array from an index array and a list of arrays to choose from.
    
    首先,如果感到困惑或不确定,请务必查看示例 - 从其完整的一般性来看,
    该函数比从下面的代码描述(下面的 ndi = `numpy.lib.index_tricks`)更简单。
    
    ``np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)])``。
    
    但这省略了一些细微之处。这里是一个完全一般的摘要:
    
    给定一个整数“索引”数组(`a`)和一个选择数组序列(`choices`),首先将 `a` 和每个选择数组广播(如果需要)到一个共同形状的数组;
    将它们分别称为 *Ba* 和 *Bchoices[i], i = 0,...,n-1*,这里必然有 ``Ba.shape == Bchoices[i].shape`` 对每个 ``i`` 成立。
    然后,根据如下方式创建一个形状为 ``Ba.shape`` 的新数组:
    
    * 如果 ``mode='raise'``(默认),则首先 `a` 的每个元素(因此 `Ba`)必须在 ``[0, n-1]`` 范围内;
      现在假设 `i`(在该范围内)是 `Ba` 中 ``(j0, j1, ..., jm)`` 位置上的值 - 则在新数组中相同位置的值是 `Bchoices[i]` 中相同位置的值;
    
    * 如果 ``mode='wrap'``,`a` 中的值(因此 `Ba`)可以是任何(有符号)整数;
      使用模算术将超出范围 ``[0, n-1]`` 的整数映射回该范围;然后像上面一样构造新数组;
    
    * 如果 ``mode='clip'``,`a` 中的值(因此 `Ba`)可以是任何(有符号)整数;
      负整数映射为 0;大于 ``n-1`` 的值映射为 ``n-1``;然后像上面一样构造新数组。
    
    Parameters
    ----------
    a : int array
        此数组必须包含 ``[0, n-1]`` 范围内的整数,其中 ``n`` 是选择数量,除非 ``mode=wrap`` 或 ``mode=clip``,在这些情况下任何整数都是允许的。
    choices : sequence of arrays
        选择数组。`a` 和所有选择数组必须可广播到相同的形状。
        如果 `choices` 本身是一个数组(不推荐),则其最外层维度(即对应于 ``choices.shape[0]`` 的维度)被视为定义的“序列”。
    out : array, optional
        如果提供,结果将插入到此数组中。它应该具有适当的形状和 dtype。
        注意,如果 ``mode='raise'``,则始终会缓冲 `out`;对于更好的性能,请使用其他模式。
    """
    pass  # 该函数暂未实现任何具体逻辑,仅有文档字符串提供函数说明
    # mode参数用于指定超出索引范围 `[0, n-1]` 的处理方式:
    # * 'raise':抛出异常
    # * 'wrap':值变为 `value mod n`
    # * 'clip':值 < 0 映射为 0,值 > n-1 映射为 n-1

    # 返回合并后的数组结果。
    merged_array : array
        The merged result.

    # 如果 `a` 和每个选择数组的形状不可广播到相同的形状,则引发 ValueError。
    ValueError: shape mismatch
        If `a` and each choice array are not all broadcastable to the same
        shape.

    # 参见等效的方法 `ndarray.choose`。
    See Also
    --------
    ndarray.choose : equivalent method
    numpy.take_along_axis : Preferable if `choices` is an array

    # 为了减少误解的可能性,即使支持以下所谓的 "滥用",`choices` 也不应该被认为是单个数组,
    # 即最外层的类似序列的容器应该是列表或元组。
    Notes
    -----
    To reduce the chance of misinterpretation, even though the following
    "abuse" is nominally supported, `choices` should neither be, nor be
    thought of as, a single array, i.e., the outermost sequence-like container
    should be either a list or a tuple.

    # 示例
    Examples
    --------

    # choices 是一个包含四个数组的列表,每个数组有四个元素
    >>> choices = [[0, 1, 2, 3], [10, 11, 12, 13],
    ...   [20, 21, 22, 23], [30, 31, 32, 33]]
    # np.choose([2, 3, 1, 0], choices) 的结果是从 choices 中第三个数组的第一个元素开始,
    # 第四个数组的第二个元素等。结果是一个一维数组 [20, 31, 12,  3]
    >>> np.choose([2, 3, 1, 0], choices)
    array([20, 31, 12,  3])
    
    # np.choose([2, 4, 1, 0], choices, mode='clip') 中,超出索引 4 被映射为 3,结果与上例相同
    >>> np.choose([2, 4, 1, 0], choices, mode='clip')
    array([20, 31, 12,  3])
    
    # np.choose([2, 4, 1, 0], choices, mode='wrap') 中,超出索引 4 被视为 4 对 4 取模,结果是 [20, 1, 12,  3]
    >>> np.choose([2, 4, 1, 0], choices, mode='wrap')
    array([20,  1, 12,  3])
    
    # 示例说明 np.choose 如何进行广播
    >>> a = [[1, 0, 1], [0, 1, 0], [1, 0, 1]]
    >>> choices = [-10, 10]
    # np.choose(a, choices) 结果是一个二维数组,通过广播选择填充结果
    >>> np.choose(a, choices)
    array([[ 10, -10,  10],
           [-10,  10, -10],
           [ 10, -10,  10]])

    >>> a = np.array([0, 1]).reshape((2,1,1))
    >>> c1 = np.array([1, 2, 3]).reshape((1,3,1))
    >>> c2 = np.array([-1, -2, -3, -4, -5]).reshape((1,1,5))
    # np.choose(a, (c1, c2)) 结果是一个三维数组,res[0,:,:]=c1, res[1,:,:]=c2
    >>> np.choose(a, (c1, c2))
    array([[[ 1,  1,  1,  1,  1],
            [ 2,  2,  2,  2,  2],
            [ 3,  3,  3,  3,  3]],
           [[-1, -2, -3, -4, -5],
            [-1, -2, -3, -4, -5],
            [-1, -2, -3, -4, -5]]])

    """
    return _wrapfunc(a, 'choose', choices, out=out, mode=mode)
# 定义一个函数 `_repeat_dispatcher`,它接受参数 `a`、`repeats` 和 `axis`,但是它仅仅返回元组 `(a,)`,未使用后续参数
def _repeat_dispatcher(a, repeats, axis=None):
    return (a,)


# 使用装饰器 `array_function_dispatch`,将函数 `repeat` 关联到 `_repeat_dispatcher` 函数
@array_function_dispatch(_repeat_dispatcher)
def repeat(a, repeats, axis=None):
    """
    重复数组中每个元素

    Parameters
    ----------
    a : array_like
        输入数组。
    repeats : int or array of ints
        每个元素的重复次数。`repeats` 会被广播以适应指定轴的形状。
    axis : int, optional
        沿着其重复值的轴。默认情况下,使用扁平化的输入数组,并返回一个扁平化的输出数组。

    Returns
    -------
    repeated_array : ndarray
        输出数组,形状与 `a` 相同,除了沿着给定轴。

    See Also
    --------
    tile : 平铺数组。
    unique : 查找数组的唯一元素。

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

    """
    # 调用 `_wrapfunc` 函数,执行实际的重复操作,并返回结果
    return _wrapfunc(a, 'repeat', repeats, axis=axis)


# 定义一个函数 `_put_dispatcher`,它接受参数 `a`、`ind`、`v` 和 `mode`,但是它仅仅返回元组 `(a, ind, v)`
def _put_dispatcher(a, ind, v, mode=None):
    return (a, ind, v)


# 使用装饰器 `array_function_dispatch`,将函数 `put` 关联到 `_put_dispatcher` 函数
@array_function_dispatch(_put_dispatcher)
def put(a, ind, v, mode='raise'):
    """
    替换数组的指定元素为给定的值。

    索引操作在扁平化的目标数组上进行。`put` 大致相当于:

    ::

        a.flat[ind] = v

    Parameters
    ----------
    a : ndarray
        目标数组。
    ind : array_like
        目标索引,解释为整数。
    v : array_like
        要放置在 `a` 中目标索引处的值。如果 `v` 比 `ind` 短,则必要时会重复。
    mode : {'raise', 'wrap', 'clip'}, optional
        指定超出边界索引的行为。

        * 'raise' -- 抛出错误(默认)
        * 'wrap' -- 环绕
        * 'clip' -- 裁剪到范围

        'clip' 模式意味着所有超出范围的索引都被替换为指向沿该轴的最后一个元素的索引。
        注意,这会禁用使用负数索引。在 'raise' 模式下,如果发生异常,目标数组仍可能被修改。

    See Also
    --------
    putmask, place
    put_along_axis : 通过匹配数组和索引数组来放置元素

    Examples
    --------
    >>> a = np.arange(5)
    >>> np.put(a, [0, 2], [-44, -55])
    >>> a
    array([-44,   1, -55,   3,   4])

    >>> a = np.arange(5)
    >>> np.put(a, 22, -5, mode='clip')
    >>> a
    array([ 0,  1,  2,  3, -5])

    """
    try:
        # 尝试获取数组 `a` 的 `put` 方法
        put = a.put
    except AttributeError as e:
        # 如果出现属性错误,抛出类型错误,说明参数 `a` 不是 `numpy.ndarray` 类型
        raise TypeError("argument 1 must be numpy.ndarray, "
                        "not {name}".format(name=type(a).__name__)) from e
    # 调用 put 函数并返回其结果
    return put(ind, v, mode=mode)
# 根据输入的参数 `a`、`axis1` 和 `axis2` 调度函数选择合适的处理函数
def _swapaxes_dispatcher(a, axis1, axis2):
    return (a,)


@array_function_dispatch(_swapaxes_dispatcher)
# 实现数组的轴交换操作
def swapaxes(a, axis1, axis2):
    """
    Interchange two axes of an array.

    Parameters
    ----------
    a : array_like
        Input array.
    axis1 : int
        First axis.
    axis2 : int
        Second axis.

    Returns
    -------
    a_swapped : ndarray
        For NumPy >= 1.10.0, if `a` is an ndarray, then a view of `a` is
        returned; otherwise a new array is created. 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.

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

    >>> x = np.array([[[0,1],[2,3]],[[4,5],[6,7]]])
    >>> x
    array([[[0, 1],
            [2, 3]],
           [[4, 5],
            [6, 7]]])

    >>> np.swapaxes(x,0,2)
    array([[[0, 4],
            [2, 6]],
           [[1, 5],
            [3, 7]]])

    """
    # 调用包装函数 `_wrapfunc` 执行实际的轴交换操作
    return _wrapfunc(a, 'swapaxes', axis1, axis2)


# 根据输入的参数 `a` 和 `axes` 调度函数选择合适的处理函数
def _transpose_dispatcher(a, axes=None):
    return (a,)


@array_function_dispatch(_transpose_dispatcher)
# 实现数组的轴转置操作
def transpose(a, axes=None):
    """
    Returns an array with axes transposed.

    For a 1-D array, this returns an unchanged view of the original array, as a
    transposed vector is simply the same vector.
    To convert a 1-D array into a 2-D column vector, an additional dimension
    must be added, e.g., ``np.atleast_2d(a).T`` achieves this, as does
    ``a[:, np.newaxis]``.
    For a 2-D array, this is the standard matrix transpose.
    For an n-D array, if axes are given, their order indicates how the
    axes are permuted (see Examples). If axes are not provided, then
    ``transpose(a).shape == a.shape[::-1]``.

    Parameters
    ----------
    a : array_like
        Input array.
    axes : tuple or list of ints, optional
        If specified, it must be a tuple or list which contains a permutation
        of [0,1,...,N-1] where N is the number of axes of `a`. The `i`'th axis
        of the returned array will correspond to the axis numbered ``axes[i]``
        of the input. If not specified, defaults to ``range(a.ndim)[::-1]``,
        which reverses the order of the axes.

    Returns
    -------
    p : ndarray
        `a` with its axes permuted. A view is returned whenever possible.

    See Also
    --------
    ndarray.transpose : Equivalent method.
    moveaxis : Move axes of an array to new positions.
    argsort : Return the indices that would sort an array.

    Notes
    -----
    Use ``transpose(a, argsort(axes))`` to invert the transposition of tensors
    when using the `axes` keyword argument.

    Examples
    --------
    >>> a = np.array([[1, 2], [3, 4]])
    >>> a
    array([[1, 2],
           [3, 4]])
    >>> np.transpose(a)
    array([[1, 3],
           [2, 4]])

    >>> a = np.array([1, 2, 3, 4])
    >>> a

    """
    # 创建一个包含四个元素的一维数组 [1, 2, 3, 4]
    >>> array([1, 2, 3, 4])
    # 对该数组进行转置操作,由于是一维数组,转置后仍然返回原数组
    >>> np.transpose(a)
    array([1, 2, 3, 4])
    
    # 创建一个形状为 (1, 2, 3) 的全为 1 的三维数组
    >>> a = np.ones((1, 2, 3))
    # 对该数组进行转置操作,指定轴的顺序为 (1, 0, 2),即原第0轴变为第1轴,原第1轴变为第0轴,第2轴保持不变
    >>> np.transpose(a, (1, 0, 2)).shape
    (2, 1, 3)
    
    # 创建一个形状为 (2, 3, 4, 5) 的全为 1 的四维数组
    >>> a = np.ones((2, 3, 4, 5))
    # 对该数组进行转置操作,返回的数组形状变为 (5, 4, 3, 2),即原数组的各轴顺序完全颠倒
    >>> np.transpose(a).shape
    (5, 4, 3, 2)
    
    """
    返回经过 _wrapfunc 函数处理后的结果,调用了 'transpose' 操作,并传入了 axes 参数
    """
    return _wrapfunc(a, 'transpose', axes)
# 返回一个包含 x 的元组,用于矩阵转置的分派器函数
def _matrix_transpose_dispatcher(x):
    return (x,)

# 使用 array_function_dispatch 装饰器将函数注册为 _matrix_transpose_dispatcher 的分派函数
@array_function_dispatch(_matrix_transpose_dispatcher)
# 定义矩阵转置函数,用于将矩阵(或矩阵堆叠)x 进行转置操作
def matrix_transpose(x, /):
    """
    Transposes a matrix (or a stack of matrices) ``x``.

    This function is Array API compatible.

    Parameters
    ----------
    x : array_like
        Input array having shape (..., M, N) and whose two innermost
        dimensions form ``MxN`` matrices.

    Returns
    -------
    out : ndarray
        An array containing the transpose for each matrix and having shape
        (..., N, M).

    See Also
    --------
    transpose : Generic transpose method.

    Examples
    --------
    >>> np.matrix_transpose([[1, 2], [3, 4]])
    array([[1, 3],
           [2, 4]])

    >>> np.matrix_transpose([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
    array([[[1, 3],
            [2, 4]],
           [[5, 7],
            [6, 8]]])

    """
    # 将输入 x 转换为 ndarray 类型
    x = asanyarray(x)
    # 如果 x 的维度小于 2,抛出异常
    if x.ndim < 2:
        raise ValueError(
            f"Input array must be at least 2-dimensional, but it is {x.ndim}"
        )
    # 交换 x 的倒数第一和倒数第二个轴,实现转置操作
    return swapaxes(x, -1, -2)


# 返回一个包含 a 的元组,用于 partition 函数的分派器函数
def _partition_dispatcher(a, kth, axis=None, kind=None, order=None):
    return (a,)

# 使用 array_function_dispatch 装饰器将函数注册为 _partition_dispatcher 的分派函数
@array_function_dispatch(_partition_dispatcher)
# 定义数组分区函数,返回数组的一个分区副本
def partition(a, kth, axis=-1, kind='introselect', order=None):
    """
    Return a partitioned copy of an array.

    Creates a copy of the array and partially sorts it in such a way that
    the value of the element in k-th position is in the position it would be
    in a sorted array. In the output array, all elements smaller than the k-th
    element are located to the left of this element and all equal or greater
    are located to its right. The ordering of the elements in the two
    partitions on the either side of the k-th element in the output array is
    undefined.

    .. versionadded:: 1.8.0

    Parameters
    ----------
    a : array_like
        Array to be sorted.
    kth : int or sequence of ints
        Element index to partition by. The k-th value of the element
        will be in its final sorted position and all smaller elements
        will be moved before it and all equal or greater elements behind
        it. The order of all elements in the partitions is undefined. If
        provided with a sequence of k-th it will partition all elements
        indexed by k-th  of them into their sorted position at once.

        .. deprecated:: 1.22.0
            Passing booleans as index is deprecated.
    axis : int or None, optional
        Axis along which to sort. If None, the array is flattened before
        sorting. The default is -1, which sorts along the last axis.
    kind : {'introselect'}, optional
        Selection algorithm. Default is 'introselect'.

    """
    # 返回数组 a 的一个分区副本,根据 kth 参数指定的位置进行分区
    return np.partition(a, kth, axis=axis, kind=kind, order=order)
    order : str or list of str, optional
        当 `a` 是一个包含字段定义的数组时,此参数指定首先比较哪些字段,第二个字段等等。
        可以将单个字段指定为字符串。不需要指定所有字段,但未指定的字段仍将按照它们在dtype中出现的顺序使用,用于解决平局。

    Returns
    -------
    partitioned_array : ndarray
        与 `a` 相同类型和形状的数组。

    See Also
    --------
    ndarray.partition : 就地对数组进行排序的方法。
    argpartition : 间接分区。
    sort : 完全排序

    Notes
    -----
    不同的选择算法由它们的平均速度、最坏情况性能、工作空间大小以及它们是否稳定来表征。稳定排序保持具有相同键的项的相对顺序不变。
    可用的算法具有以下属性:

    ================= ======= ============= ============ =======
       kind            speed   worst case    work space  stable
    ================= ======= ============= ============ =======
    'introselect'        1        O(n)           0         no
    ================= ======= ============= ============ =======

    所有分区算法在除了最后一个轴以外的任何轴上进行分区时都会对数据进行临时复制。
    因此,沿着最后一个轴进行分区比沿着其他任何轴快,并且使用的空间更少。

    对于复数,排序顺序是词典顺序的。如果实部和虚部均为非nan,则顺序由实部决定,除非它们相等,在这种情况下,顺序由虚部决定。

    Examples
    --------
    >>> a = np.array([7, 1, 7, 7, 1, 5, 7, 2, 3, 2, 6, 2, 3, 0])
    >>> p = np.partition(a, 4)
    >>> p
    array([0, 1, 2, 1, 2, 5, 2, 3, 3, 6, 7, 7, 7, 7]) # 结果可能有所不同

    ``p[4]`` 是 2; ``p[:4]`` 中的所有元素都小于或等于 ``p[4]``, ``p[5:]`` 中的所有元素都大于或等于 ``p[4]``。分区如下:

        [0, 1, 2, 1], [2], [5, 2, 3, 3, 6, 7, 7, 7, 7]

    下面的示例展示了对 `kth` 传递多个值的使用。

    >>> p2 = np.partition(a, (4, 8))
    >>> p2
    array([0, 1, 2, 1, 2, 3, 3, 2, 5, 6, 7, 7, 7, 7])

    ``p2[4]`` 是 2, ``p2[8]`` 是 5。 ``p2[:4]`` 中的所有元素都小于或等于 ``p2[4]``,
    ``p2[5:8]`` 中的所有元素大于或等于 ``p2[4]`` 且小于或等于 ``p2[8]``, ``p2[9:]`` 中的所有元素大于或等于 ``p2[8]``。分区如下:

        [0, 1, 2, 1], [2], [3, 3, 2], [5], [6, 7, 7, 7, 7]
    """
    if axis is None:
        # 对于 np.matrix,flatten 返回 (1, N),因此始终使用最后一个轴
        a = asanyarray(a).flatten()
        axis = -1
    else:
        # 使用 'K' 顺序对数组进行复制,保证 C 和 Fortran 顺序的最优性能
        a = asanyarray(a).copy(order="K")
    # 使用数组 a 的 partition 方法,根据给定的 kth 值对数组进行分区操作
    a.partition(kth, axis=axis, kind=kind, order=order)
    # 返回分区后的数组 a,该操作会直接修改数组 a 的内容
    return a
# 定义一个分派函数,用于确定 argpartition 函数的参数类型和位置
def _argpartition_dispatcher(a, kth, axis=None, kind=None, order=None):
    # 返回参数 a,这里仅用于分派作用
    return (a,)


# 使用 array_function_dispatch 装饰器将 _argpartition_dispatcher 与 argpartition 函数关联起来
@array_function_dispatch(_argpartition_dispatcher)
# 定义 argpartition 函数,用于沿指定轴使用给定的算法进行间接分区
def argpartition(a, kth, axis=-1, kind='introselect', order=None):
    """
    Perform an indirect partition along the given axis using the
    algorithm specified by the `kind` keyword. It returns an array of
    indices of the same shape as `a` that index data along the given
    axis in partitioned order.

    .. versionadded:: 1.8.0

    Parameters
    ----------
    a : array_like
        Array to sort.
    kth : int or sequence of ints
        Element index to partition by. The k-th element will be in its
        final sorted position and all smaller elements will be moved
        before it and all larger elements behind it. The order of all
        elements in the partitions is undefined. If provided with a
        sequence of k-th it will partition all of them into their sorted
        position at once.

        .. deprecated:: 1.22.0
            Passing booleans as index is deprecated.
    axis : int or None, optional
        Axis along which to sort. The default is -1 (the last axis). If
        None, the flattened array is used.
    kind : {'introselect'}, optional
        Selection algorithm. Default is 'introselect'
    order : str or list of str, optional
        When `a` is an array with fields defined, this argument
        specifies which fields to compare first, second, etc. A single
        field can be specified as a string, and not all fields need be
        specified, but unspecified fields will still be used, in the
        order in which they come up in the dtype, to break ties.

    Returns
    -------
    index_array : ndarray, int
        Array of indices that partition `a` along the specified axis.
        If `a` is one-dimensional, ``a[index_array]`` yields a partitioned `a`.
        More generally, ``np.take_along_axis(a, index_array, axis=axis)``
        always yields the partitioned `a`, irrespective of dimensionality.

    See Also
    --------
    partition : Describes partition algorithms used.
    ndarray.partition : Inplace partition.
    argsort : Full indirect sort.
    take_along_axis : Apply ``index_array`` from argpartition
                      to an array as if by calling partition.

    Notes
    -----
    See `partition` for notes on the different selection algorithms.

    Examples
    --------
    One dimensional array:

    >>> x = np.array([3, 4, 2, 1])
    >>> x[np.argpartition(x, 3)]
    array([2, 1, 3, 4]) # may vary
    >>> x[np.argpartition(x, (1, 3))]
    array([1, 2, 3, 4]) # may vary

    >>> x = [3, 4, 2, 1]
    >>> np.array(x)[np.argpartition(x, 3)]
    array([2, 1, 3, 4]) # may vary

    Multi-dimensional array:

    >>> x = np.array([[3, 4, 2], [1, 3, 1]])
    >>> index_array = np.argpartition(x, kth=1, axis=-1)
    >>> # below is the same as np.partition(x, kth=1)
    >>> np.take_along_axis(x, index_array, axis=-1)
    """
    # 创建一个二维数组,包含两个行和三个列的整数数据
    array([[2, 3, 4],
           [1, 1, 3]])
    
    # 返回调用 _wrapfunc 函数的结果,调用参数包括数组 a、函数名 'argpartition'、
    # 分割位置 kth、轴向 axis、分割方式 kind、排序方式 order
    return _wrapfunc(a, 'argpartition', kth, axis=axis, kind=kind, order=order)
# 定义一个排序调度器函数,接受多个参数并返回它们的元组
def _sort_dispatcher(a, axis=None, kind=None, order=None, *, stable=None):
    return (a,)


# 使用装饰器array_function_dispatch将_sort_dispatcher函数与sort函数关联起来
@array_function_dispatch(_sort_dispatcher)
def sort(a, axis=-1, kind=None, order=None, *, stable=None):
    """
    Return a sorted copy of an array.

    Parameters
    ----------
    a : array_like
        Array to be sorted.
    axis : int or None, optional
        Axis along which to sort. If None, the array is flattened before
        sorting. The default is -1, which sorts along the last axis.
    kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
        Sorting algorithm. The default is 'quicksort'. Note that both 'stable'
        and 'mergesort' use timsort or radix sort under the covers and,
        in general, the actual implementation will vary with data type.
        The 'mergesort' option is retained for backwards compatibility.

        .. versionchanged:: 1.15.0.
           The 'stable' option was added.

    order : str or list of str, optional
        When `a` is an array with fields defined, this argument specifies
        which fields to compare first, second, etc.  A single field can
        be specified as a string, and not all fields need be specified,
        but unspecified fields will still be used, in the order in which
        they come up in the dtype, to break ties.
    stable : bool, optional
        Sort stability. If ``True``, the returned array will maintain
        the relative order of ``a`` values which compare as equal.
        If ``False`` or ``None``, this is not guaranteed. Internally,
        this option selects ``kind='stable'``. Default: ``None``.

        .. versionadded:: 2.0.0

    Returns
    -------
    sorted_array : ndarray
        Array of the same type and shape as `a`.

    See Also
    --------
    ndarray.sort : Method to sort an array in-place.
    argsort : Indirect sort.
    lexsort : Indirect stable sort on multiple keys.
    searchsorted : Find elements in a sorted array.
    partition : Partial sort.

    Notes
    -----
    The various sorting algorithms are characterized by their average speed,
    worst case performance, work space size, and whether they are stable. A
    stable sort keeps items with the same key in the same relative
    order. The four algorithms implemented in NumPy have the following
    properties:

    =========== ======= ============= ============ ========
       kind      speed   worst case    work space   stable
    =========== ======= ============= ============ ========
    'quicksort'    1     O(n^2)            0          no
    'heapsort'     3     O(n*log(n))       0          no
    'mergesort'    2     O(n*log(n))      ~n/2        yes
    'timsort'      2     O(n*log(n))      ~n/2        yes
    =========== ======= ============= ============ ========

    .. note:: The datatype determines which of 'mergesort' or 'timsort'
       is actually used, even if 'mergesort' is specified. User selection
       at a finer scale is not currently available.
    """
    # 返回通过指定参数进行排序后的数组的副本
    return (a,)
    For performance, ``sort`` makes a temporary copy if needed to make the data
    `contiguous <https://numpy.org/doc/stable/glossary.html#term-contiguous>`_
    in memory along the sort axis. For even better performance and reduced
    memory consumption, ensure that the array is already contiguous along the
    sort axis.

    The sort order for complex numbers is lexicographic. If both the real
    and imaginary parts are non-nan then the order is determined by the
    real parts except when they are equal, in which case the order is
    determined by the imaginary parts.

    Previous to numpy 1.4.0 sorting real and complex arrays containing nan
    values led to undefined behaviour. In numpy versions >= 1.4.0 nan
    values are sorted to the end. The extended sort order is:

      * Real: [R, nan]
      * Complex: [R + Rj, R + nanj, nan + Rj, nan + nanj]

    where R is a non-nan real value. Complex values with the same nan
    placements are sorted according to the non-nan part if it exists.
    Non-nan values are sorted as before.

    .. versionadded:: 1.12.0

    quicksort has been changed to:
    `introsort <https://en.wikipedia.org/wiki/Introsort>`_.
    When sorting does not make enough progress it switches to
    `heapsort <https://en.wikipedia.org/wiki/Heapsort>`_.
    This implementation makes quicksort O(n*log(n)) in the worst case.

    'stable' automatically chooses the best stable sorting algorithm
    for the data type being sorted.
    It, along with 'mergesort' is currently mapped to
    `timsort <https://en.wikipedia.org/wiki/Timsort>`_
    or `radix sort <https://en.wikipedia.org/wiki/Radix_sort>`_
    depending on the data type.
    API forward compatibility currently limits the
    ability to select the implementation and it is hardwired for the different
    data types.

    .. versionadded:: 1.17.0

    Timsort is added for better performance on already or nearly
    sorted data. On random data timsort is almost identical to
    mergesort. It is now used for stable sort while quicksort is still the
    default sort if none is chosen. For timsort details, refer to
    `CPython listsort.txt
    <https://github.com/python/cpython/blob/3.7/Objects/listsort.txt>`_
    'mergesort' and 'stable' are mapped to radix sort for integer data types.
    Radix sort is an O(n) sort instead of O(n log n).

    .. versionchanged:: 1.18.0

    NaT now sorts to the end of arrays for consistency with NaN.

    Examples
    --------
    >>> a = np.array([[1,4],[3,1]])
    >>> np.sort(a)                # sort along the last axis
    array([[1, 4],
           [1, 3]])
    >>> np.sort(a, axis=None)     # sort the flattened array
    array([1, 1, 3, 4])
    >>> np.sort(a, axis=0)        # sort along the first axis
    array([[1, 1],
           [3, 4]])

    Use the `order` keyword to specify a field to use when sorting a
    structured array:

    >>> dtype = [('name', 'S10'), ('height', float), ('age', int)]
    if axis is None:
        # 如果未指定轴,则将数组展平为一维数组
        a = asanyarray(a).flatten()
        # 设定轴为最后一个维度
        axis = -1
    else:
        # 如果指定了轴,则创建数组的副本,并按照内存中的顺序复制元素
        a = asanyarray(a).copy(order="K")
    # 对数组按照指定的轴进行排序,支持不同的排序算法和顺序
    a.sort(axis=axis, kind=kind, order=order, stable=stable)
    # 返回排序后的数组
    return a
# 为 _argsort_dispatcher 函数创建一个分发器,用于根据参数类型调度合适的处理函数
def _argsort_dispatcher(a, axis=None, kind=None, order=None, *, stable=None):
    # 返回参数元组 (a,)
    return (a,)

# 使用 array_function_dispatch 装饰器将 argsort 函数注册到数组函数的分发系统中
@array_function_dispatch(_argsort_dispatcher)
def argsort(a, axis=-1, kind=None, order=None, *, stable=None):
    """
    返回对数组排序后的索引。

    在指定的轴上使用给定的排序算法执行间接排序。它返回与数组 `a` 相同形状的索引数组,
    该数组按排序顺序索引数据。

    Parameters
    ----------
    a : array_like
        待排序的数组。
    axis : int or None, optional
        要排序的轴。默认为 -1(最后一个轴)。如果为 None,则使用扁平化的数组。
    kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
        排序算法。默认为 'quicksort'。注意 'stable''mergesort' 选项在内部使用 timsort,
        并且实际实现会根据数据类型而变化。保留 'mergesort' 选项是为了向后兼容性。

        .. versionchanged:: 1.15.0.
           添加了 'stable' 选项。
    order : str or list of str, optional
        当 `a` 是一个有字段定义的数组时,此参数指定首先比较哪些字段、第二个字段等。
        可以将单个字段指定为字符串,不需要指定所有字段,但未指定的字段仍将按它们在 dtype 中出现的顺序使用来打破平局。
    stable : bool, optional
        排序稳定性。如果为 ``True``,返回的数组将保持 ``a`` 值的相对顺序,这些值被视为相等。
        如果为 ``False`` 或 ``None``,则不能保证这一点。在内部,此选项选择 ``kind='stable'``。默认为 ``None``。

        .. versionadded:: 2.0.0

    Returns
    -------
    index_array : ndarray, int
        沿指定 `axis` 排序 `a` 的索引数组。
        如果 `a` 是一维的,则 ``a[index_array]`` 返回一个排序后的 `a`。
        更一般地,``np.take_along_axis(a, index_array, axis=axis)`` 始终返回排序后的 `a`,无论其维度如何。

    See Also
    --------
    sort : 描述使用的排序算法。
    lexsort : 使用多个键进行间接稳定排序。
    ndarray.sort : 原地排序。
    argpartition : 间接部分排序。
    take_along_axis : 将来自 argsort 的 ``index_array`` 应用于数组,就像调用 sort 一样。

    Notes
    -----
    有关不同排序算法的注意事项,请参见 `sort`。

    从 NumPy 1.4.0 开始,`argsort` 可与包含 NaN 值的实数/复数数组一起工作。增强的排序顺序在 `sort` 中有文档记录。

    Examples
    --------
    一维数组:

    >>> x = np.array([3, 1, 2])
    >>> np.argsort(x)
    array([1, 2, 0])

    二维数组:

    >>> x = np.array([[0, 3], [2, 2]])
    >>> x
    array([[0, 3],
           [2, 2]])

    """
    # 对数组 x 按照第一个轴(沿着列)进行排序,返回排序后元素的索引
    ind = np.argsort(x, axis=0)
    # 输出排序后的索引数组
    ind
    # 沿着第一个轴(列)取出排序后的数组元素,等同于 np.sort(x, axis=0)
    np.take_along_axis(x, ind, axis=0)

    # 对数组 x 按照最后一个轴(沿着行)进行排序,返回排序后元素的索引
    ind = np.argsort(x, axis=1)
    # 输出排序后的索引数组
    ind
    # 沿着最后一个轴(行)取出排序后的数组元素,等同于 np.sort(x, axis=1)
    np.take_along_axis(x, ind, axis=1)

    # 返回一个元组,包含按照展开数组 x 后的元素排序的索引数组
    ind = np.unravel_index(np.argsort(x, axis=None), x.shape)
    # 输出展开数组排序后的索引元组
    ind
    # 根据排序后的索引元组获取排序后的数组元素,等同于 np.sort(x, axis=None)
    x[ind]

    # 使用自定义字段进行排序的示例:
    # 创建一个结构化数组 x,包含两个字段 'x' 和 'y'
    x = np.array([(1, 0), (0, 1)], dtype=[('x', '<i4'), ('y', '<i4')])
    # 输出结构化数组 x
    x

    # 按照字段 ('x', 'y') 的顺序对数组 x 进行排序,返回排序后元素的索引
    np.argsort(x, order=('x', 'y'))

    # 按照字段 ('y', 'x') 的顺序对数组 x 进行排序,返回排序后元素的索引
    np.argsort(x, order=('y', 'x'))

    """
    # 调用 _wrapfunc 函数,传递参数进行数组排序操作
    return _wrapfunc(
        a, 'argsort', axis=axis, kind=kind, order=order, stable=stable
    )
# 根据参数生成一个分发函数 _argmax_dispatcher,返回元组 (a, out)
def _argmax_dispatcher(a, axis=None, out=None, *, keepdims=np._NoValue):
    return (a, out)


# 使用装饰器 array_function_dispatch 将 argmax 函数与 _argmax_dispatcher 分发函数关联起来
@array_function_dispatch(_argmax_dispatcher)
def argmax(a, axis=None, out=None, *, keepdims=np._NoValue):
    """
    Returns the indices of the maximum values along an axis.

    Parameters
    ----------
    a : array_like
        Input array.
    axis : int, optional
        By default, the index is into the flattened array, otherwise
        along the specified axis.
    out : array, optional
        If provided, the result will be inserted into this array. It should
        be of the appropriate shape and dtype.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the array.

        .. versionadded:: 1.22.0

    Returns
    -------
    index_array : ndarray of ints
        Array of indices into the array. It has the same shape as ``a.shape``
        with the dimension along `axis` removed. If `keepdims` is set to True,
        then the size of `axis` will be 1 with the resulting array having same
        shape as ``a.shape``.

    See Also
    --------
    ndarray.argmax, argmin
    amax : The maximum value along a given axis.
    unravel_index : Convert a flat index into an index tuple.
    take_along_axis : Apply ``np.expand_dims(index_array, axis)``
                      from argmax to an array as if by calling max.

    Notes
    -----
    In case of multiple occurrences of the maximum values, the indices
    corresponding to the first occurrence are returned.

    Examples
    --------
    >>> a = np.arange(6).reshape(2,3) + 10
    >>> a
    array([[10, 11, 12],
           [13, 14, 15]])
    >>> np.argmax(a)
    5
    >>> np.argmax(a, axis=0)
    array([1, 1, 1])
    >>> np.argmax(a, axis=1)
    array([2, 2])

    Indexes of the maximal elements of a N-dimensional array:

    >>> ind = np.unravel_index(np.argmax(a, axis=None), a.shape)
    >>> ind
    (1, 2)
    >>> a[ind]
    15

    >>> b = np.arange(6)
    >>> b[1] = 5
    >>> b
    array([0, 5, 2, 3, 4, 5])
    >>> np.argmax(b)  # Only the first occurrence is returned.
    1

    >>> x = np.array([[4,2,3], [1,0,3]])
    >>> index_array = np.argmax(x, axis=-1)
    >>> # Same as np.amax(x, axis=-1, keepdims=True)
    >>> np.take_along_axis(x, np.expand_dims(index_array, axis=-1), axis=-1)
    array([[4],
           [3]])
    >>> # Same as np.amax(x, axis=-1)
    >>> np.take_along_axis(x, np.expand_dims(index_array, axis=-1),
    ...     axis=-1).squeeze(axis=-1)
    array([4, 3])

    Setting `keepdims` to `True`,

    >>> x = np.arange(24).reshape((2, 3, 4))
    >>> res = np.argmax(x, axis=1, keepdims=True)
    >>> res.shape
    (2, 1, 4)
    """
    # 如果 keepdims 是 np._NoValue,将其作为空字典传递给 _wrapfunc 函数
    kwds = {'keepdims': keepdims} if keepdims is not np._NoValue else {}
    # 调用 _wrapfunc 函数,传递相应的参数和关键字参数
    return _wrapfunc(a, 'argmax', axis=axis, out=out, **kwds)
# 定义一个分派函数 _argmin_dispatcher,返回元组 (a, out)
def _argmin_dispatcher(a, axis=None, out=None, *, keepdims=np._NoValue):
    return (a, out)


# 使用 array_function_dispatch 装饰器将 argmin 函数分派给 _argmin_dispatcher 函数
@array_function_dispatch(_argmin_dispatcher)
def argmin(a, axis=None, out=None, *, keepdims=np._NoValue):
    """
    返回沿指定轴的最小值的索引。

    Parameters
    ----------
    a : array_like
        输入数组。
    axis : int, optional
        默认情况下,索引是在展平数组中,否则沿指定的轴。
    out : array, optional
        如果提供,则结果将插入到此数组中。它应该具有适当的形状和dtype。
    keepdims : bool, optional
        如果设置为True,则减少的轴将作为大小为一的维度保留在结果中。使用此选项,
        结果将正确地与数组广播。

        .. versionadded:: 1.22.0

    Returns
    -------
    index_array : ndarray of ints
        数组中的索引数组。它具有与 `a.shape` 相同的形状,沿 `axis` 的维度被移除。如果 `keepdims` 设置为True,
        那么轴的大小将为1,生成的数组将具有与 `a.shape` 相同的形状。

    See Also
    --------
    ndarray.argmin, argmax
    amin : 沿指定轴的最小值。
    unravel_index : 将平坦索引转换为索引元组。
    take_along_axis : 将 ``np.expand_dims(index_array, axis)`` 从 argmin 应用于数组,就像调用 min 一样。

    Notes
    -----
    对于最小值的多个出现情况,返回与第一次出现相对应的索引。

    Examples
    --------
    >>> a = np.arange(6).reshape(2,3) + 10
    >>> a
    array([[10, 11, 12],
           [13, 14, 15]])
    >>> np.argmin(a)
    0
    >>> np.argmin(a, axis=0)
    array([0, 0, 0])
    >>> np.argmin(a, axis=1)
    array([0, 0])

    N 维数组的最小元素的索引:

    >>> ind = np.unravel_index(np.argmin(a, axis=None), a.shape)
    >>> ind
    (0, 0)
    >>> a[ind]
    10

    >>> b = np.arange(6) + 10
    >>> b[4] = 10
    >>> b
    array([10, 11, 12, 13, 10, 15])
    >>> np.argmin(b)  # 仅返回第一次出现的最小值的索引。
    0

    >>> x = np.array([[4,2,3], [1,0,3]])
    >>> index_array = np.argmin(x, axis=-1)
    >>> # 等同于 np.amin(x, axis=-1, keepdims=True)
    >>> np.take_along_axis(x, np.expand_dims(index_array, axis=-1), axis=-1)
    array([[2],
           [0]])
    >>> # 等同于 np.amax(x, axis=-1)
    >>> np.take_along_axis(x, np.expand_dims(index_array, axis=-1),
    ...     axis=-1).squeeze(axis=-1)
    array([2, 0])

    设置 `keepdims` 为 `True`,

    >>> x = np.arange(24).reshape((2, 3, 4))
    >>> res = np.argmin(x, axis=1, keepdims=True)
    >>> res.shape
    (2, 1, 4)
    """
    # 如果 keepdims 是 np._NoValue,则创建空字典 kwds,否则创建包含 keepdims 的字典 kwds
    kwds = {'keepdims': keepdims} if keepdims is not np._NoValue else {}
    # 调用 _wrapfunc 函数,传递参数 a, 'argmin', axis=axis, out=out 和 kwds 中的关键字参数
    return _wrapfunc(a, 'argmin', axis=axis, out=out, **kwds)
# 定义一个分派函数 _searchsorted_dispatcher,用于将参数传递给 searchsorted 函数
def _searchsorted_dispatcher(a, v, side=None, sorter=None):
    return (a, v, sorter)

# 使用装饰器 array_function_dispatch 将 _searchsorted_dispatcher 作为分派函数与 searchsorted 函数关联
@array_function_dispatch(_searchsorted_dispatcher)
def searchsorted(a, v, side='left', sorter=None):
    """
    Find indices where elements should be inserted to maintain order.

    Find the indices into a sorted array `a` such that, if the
    corresponding elements in `v` were inserted before the indices, the
    order of `a` would be preserved.

    Assuming that `a` is sorted:

    ======  ============================
    `side`  returned index `i` satisfies
    ======  ============================
    left    ``a[i-1] < v <= a[i]``
    right   ``a[i-1] <= v < a[i]``
    ======  ============================

    Parameters
    ----------
    a : 1-D array_like
        Input array. If `sorter` is None, then it must be sorted in
        ascending order, otherwise `sorter` must be an array of indices
        that sort it.
    v : array_like
        Values to insert into `a`.
    side : {'left', 'right'}, optional
        If 'left', the index of the first suitable location found is given.
        If 'right', return the last such index.  If there is no suitable
        index, return either 0 or N (where N is the length of `a`).
    sorter : 1-D array_like, optional
        Optional array of integer indices that sort array a into ascending
        order. They are typically the result of argsort.

        .. versionadded:: 1.7.0

    Returns
    -------
    indices : int or array of ints
        Array of insertion points with the same shape as `v`,
        or an integer if `v` is a scalar.

    See Also
    --------
    sort : Return a sorted copy of an array.
    histogram : Produce histogram from 1-D data.

    Notes
    -----
    Binary search is used to find the required insertion points.

    As of NumPy 1.4.0 `searchsorted` works with real/complex arrays containing
    `nan` values. The enhanced sort order is documented in `sort`.

    This function uses the same algorithm as the builtin python
    `bisect.bisect_left` (``side='left'``) and `bisect.bisect_right`
    (``side='right'``) functions, which is also vectorized
    in the `v` argument.

    Examples
    --------
    >>> np.searchsorted([11,12,13,14,15], 13)
    2
    >>> np.searchsorted([11,12,13,14,15], 13, side='right')
    3
    >>> np.searchsorted([11,12,13,14,15], [-10, 20, 12, 13])
    array([0, 5, 1, 2])

    """
    # 调用 _wrapfunc 函数,将参数传递给其它函数进行处理,返回处理结果
    return _wrapfunc(a, 'searchsorted', v, side=side, sorter=sorter)


# 定义一个分派函数 _resize_dispatcher,用于将参数传递给 resize 函数
def _resize_dispatcher(a, new_shape):
    return (a,)

# 使用装饰器 array_function_dispatch 将 _resize_dispatcher 作为分派函数与 resize 函数关联
@array_function_dispatch(_resize_dispatcher)
def resize(a, new_shape):
    """
    Return a new array with the specified shape.

    If the new array is larger than the original array, then the new
    array is filled with repeated copies of `a`.  Note that this behavior
    is different from a.resize(new_shape) which fills with zeros instead
    of repeated copies of `a`.

    Parameters
    ----------
    a : array_like
        Array to be resized.

    new_shape : tuple of ints
        The new shape should be compatible with the original shape. If
        an integer, then the result will be a 1-D array of that length.
        One shape dimension can be -1. In this case, the value is
        inferred from the length of the array and remaining dimensions.

    Returns
    -------
    reshaped_array : ndarray
        The new array with the specified shape.

    Examples
    --------
    >>> a = np.array([[0, 1], [2, 3]])
    >>> np.resize(a, (2,3))
    array([[0, 1, 2],
           [3, 0, 1]])
    >>> np.resize(a, (1,4))
    array([[0, 1, 2, 3]])
    >>> np.resize(a,(2, 1))
    array([[0],
           [1]])

    """
    # 返回调用 _wrapfunc 函数后的结果,将参数传递给其它函数进行处理
    return _wrapfunc(a, 'resize', new_shape)
    new_shape : int or tuple of int
        # 定义参数 new_shape,可以是单个整数或整数元组,表示重置后数组的形状。

    Returns
    -------
    reshaped_array : ndarray
        # 返回重塑后的数组,从旧数组的数据中形成,必要时重复以填充所需的元素数。数据按C顺序重复。

    See Also
    --------
    numpy.reshape : 不改变总大小的情况下重塑数组。
    numpy.pad : 扩展和填充数组。
    numpy.repeat : 重复数组的元素。
    ndarray.resize : 就地调整数组大小。

    Notes
    -----
    当数组的总大小不变时,应使用 `~numpy.reshape`。在大多数其他情况下,索引(用于减小大小)或填充(用于增加大小)可能是更合适的解决方案。

    Warning: 此功能 **不** 单独考虑轴,即不应用插值/外推。它填充返回数组以满足所需的元素数,在C顺序下迭代 `a`,忽略轴(如果新形状较大,则从开始处循环)。因此,此功能不适合调整图像或每个轴表示独立和不同实体的数据。

    Examples
    --------
    >>> a=np.array([[0,1],[2,3]])
    >>> np.resize(a,(2,3))
    array([[0, 1, 2],
           [3, 0, 1]])
    >>> np.resize(a,(1,4))
    array([[0, 1, 2, 3]])
    >>> np.resize(a,(2,4))
    array([[0, 1, 2, 3],
           [0, 1, 2, 3]])

    """
    if isinstance(new_shape, (int, nt.integer)):
        # 如果 new_shape 是整数或整数类型,则转换为元组形式
        new_shape = (new_shape,)

    a = ravel(a)

    new_size = 1
    for dim_length in new_shape:
        # 计算新形状下的总大小
        new_size *= dim_length
        if dim_length < 0:
            raise ValueError(
                'all elements of `new_shape` must be non-negative'
            )

    if a.size == 0 or new_size == 0:
        # 如果原始数组或新大小为零,返回一个与 a 类型和形状相同的零数组
        return np.zeros_like(a, shape=new_shape)

    repeats = -(-new_size // a.size)  # ceil division,计算重复次数
    a = concatenate((a,) * repeats)[:new_size]  # 将数组按重复次数连接,并截取所需长度

    return reshape(a, new_shape)
# 创建一个分发器函数 _squeeze_dispatcher,接受参数 a 和 axis,并返回一个包含 a 的元组
def _squeeze_dispatcher(a, axis=None):
    # 返回一个元组,包含参数 a
    return (a,)


# 使用 array_function_dispatch 装饰器将 _squeeze_dispatcher 应用于 squeeze 函数
@array_function_dispatch(_squeeze_dispatcher)
def squeeze(a, axis=None):
    """
    Remove axes of length one from `a`.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        .. versionadded:: 1.7.0

        Selects a subset of the entries of length one in the
        shape. If an axis is selected with shape entry greater than
        one, an error is raised.

    Returns
    -------
    squeezed : ndarray
        The input array, but with all or a subset of the
        dimensions of length 1 removed. This is always `a` itself
        or a view into `a`. Note that if all axes are squeezed,
        the result is a 0d array and not a scalar.

    Raises
    ------
    ValueError
        If `axis` is not None, and an axis being squeezed is not of length 1

    See Also
    --------
    expand_dims : The inverse operation, adding entries of length one
    reshape : Insert, remove, and combine dimensions, and resize existing ones

    Examples
    --------
    >>> x = np.array([[[0], [1], [2]]])
    >>> x.shape
    (1, 3, 1)
    >>> np.squeeze(x).shape
    (3,)
    >>> np.squeeze(x, axis=0).shape
    (3, 1)
    >>> np.squeeze(x, axis=1).shape
    Traceback (most recent call last):
    ...
    ValueError: cannot select an axis to squeeze out which has size
    not equal to one
    >>> np.squeeze(x, axis=2).shape
    (1, 3)
    >>> x = np.array([[1234]])
    >>> x.shape
    (1, 1)
    >>> np.squeeze(x)
    array(1234)  # 0d array
    >>> np.squeeze(x).shape
    ()
    >>> np.squeeze(x)[()]
    1234

    """
    # 尝试获取参数 a 的 squeeze 方法,如果不存在则调用 _wrapit 函数包装并返回结果
    try:
        squeeze = a.squeeze
    except AttributeError:
        return _wrapit(a, 'squeeze', axis=axis)
    # 如果 axis 为 None,则调用 squeeze() 方法
    if axis is None:
        return squeeze()
    else:
        # 否则,调用 squeeze(axis=axis) 方法
        return squeeze(axis=axis)


# 创建一个分发器函数 _diagonal_dispatcher,接受参数 a, offset, axis1, axis2,并返回一个包含 a 的元组
def _diagonal_dispatcher(a, offset=None, axis1=None, axis2=None):
    # 返回一个元组,包含参数 a
    return (a,)


# 使用 array_function_dispatch 装饰器将 _diagonal_dispatcher 应用于 diagonal 函数
@array_function_dispatch(_diagonal_dispatcher)
def diagonal(a, offset=0, axis1=0, axis2=1):
    """
    Return specified diagonals.

    If `a` is 2-D, returns the diagonal of `a` with the given offset,
    i.e., the collection of elements of the form ``a[i, i+offset]``.  If
    `a` has more than two dimensions, then the axes specified by `axis1`
    and `axis2` are used to determine the 2-D sub-array whose diagonal is
    returned.  The shape of the resulting array can be determined by
    removing `axis1` and `axis2` and appending an index to the right equal
    to the size of the resulting diagonals.

    In versions of NumPy prior to 1.7, this function always returned a new,
    independent array containing a copy of the values in the diagonal.

    In NumPy 1.7 and 1.8, it continues to return a copy of the diagonal,
    but depending on this fact is deprecated. Writing to the resulting
    array continues to work as it used to, but a FutureWarning is issued.
    """
    # 这里缺少返回值的部分,需要注意补充上相关代码和注释
    # Starting in NumPy 1.9, np.diagonal() returns a read-only view of the original array's diagonals.
    # Attempts to modify this view will result in an error.
    
    # In a future release of NumPy, np.diagonal() may return a read/write view, allowing modifications
    # to affect the original array. The returned array will maintain the same type as the input array.
    
    # If you do not intend to modify the array returned by np.diagonal(), you can disregard the above
    # considerations.
    
    # If your code relies on the current read-only behavior, it's recommended to explicitly copy the
    # returned array, e.g., use np.diagonal(a).copy() instead of np.diagonal(a). This ensures
    # compatibility with both current and future versions of NumPy.
    
    # Parameters:
    # a : array_like
    #     Input array from which diagonals are extracted.
    # offset : int, optional
    #     Offset of the diagonal from the main diagonal. Can be positive or negative. Defaults to 0.
    # axis1 : int, optional
    #     First axis of the 2-D sub-arrays from which diagonals should be taken. Defaults to 0.
    # axis2 : int, optional
    #     Second axis of the 2-D sub-arrays from which diagonals should be taken. Defaults to 1.
    
    # Returns:
    # -------
    # array_of_diagonals : ndarray
    #     If `a` is 2-D, a 1-D array containing the diagonals of `a` of the same type.
    #     If `a` has more than 2 dimensions, dimensions specified by `axis1` and `axis2` are removed,
    #     and a new axis is inserted at the end corresponding to the diagonal.
    
    # Raises:
    # ------
    # ValueError
    #     If `a` has less than 2 dimensions.
    
    # See Also:
    # --------
    # diag : Extract diagonals as a new 1-D array.
    # diagflat : Create diagonal arrays.
    # trace : Sum along diagonals.
    
    # Examples:
    # ---------
    # Example 1: 2-D array
    # >>> a = np.arange(4).reshape(2,2)
    # >>> a
    # array([[0, 1],
    #        [2, 3]])
    # >>> a.diagonal()
    # array([0, 3])
    # >>> a.diagonal(1)
    # array([1])
    
    # Example 2: 3-D array
    # >>> a = np.arange(8).reshape(2,2,2)
    # >>> a
    # array([[[0, 1],
    #         [2, 3]],
    #        [[4, 5],
    #         [6, 7]]])
    # >>> a.diagonal(0, 0, 1)
    # array([[0, 6],
    #        [1, 7]])
    
    # Explanation:
    # The function `np.diagonal()` extracts diagonals from arrays of various dimensions,
    # supporting multi-dimensional slicing through `axis1` and `axis2` parameters.
    The anti-diagonal can be obtained by reversing the order of elements
    using either `numpy.flipud` or `numpy.fliplr`.

    >>> a = np.arange(9).reshape(3, 3)
    >>> a
    array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])
    >>> np.fliplr(a).diagonal()  # Horizontal flip
    array([2, 4, 6])
    >>> np.flipud(a).diagonal()  # Vertical flip
    array([6, 4, 2])

    Note that the order in which the diagonal is retrieved varies depending
    on the flip function.
    """
    # 如果输入的数组是一个 numpy 矩阵(matrix),则将其对角线转换为 1 维数组,以保持向后兼容性。
    if isinstance(a, np.matrix):
        return asarray(a).diagonal(offset=offset, axis1=axis1, axis2=axis2)
    else:
        # 如果输入的数组不是矩阵,则将其转换为任意数组(asanyarray)再提取对角线元素。
        return asanyarray(a).diagonal(offset=offset, axis1=axis1, axis2=axis2)
# 定义一个函数 _trace_dispatcher,用于调度 trace 函数的参数
def _trace_dispatcher(
        a, offset=None, axis1=None, axis2=None, dtype=None, out=None):
    # 返回元组 (a, out),作为 trace 函数的参数
    return (a, out)


# 使用 array_function_dispatch 装饰器定义 trace 函数
@array_function_dispatch(_trace_dispatcher)
def trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None):
    """
    返回数组对角线上的元素之和。

    如果 `a` 是二维数组,返回指定偏移量的主对角线元素之和,即所有 `a[i, i+offset]` 的和。

    如果 `a` 的维度高于二维,则使用指定的 axis1 和 axis2 参数确定要返回其对角线的二维子数组。
    返回数组的形状与 `a` 的形状相同,但移除了 axis1 和 axis2。

    参数
    ----------
    a : array_like
        输入数组,提取对角线元素。
    offset : int, optional
        主对角线的偏移量。可以是正数或负数。默认为 0。
    axis1, axis2 : int, optional
        用于提取对角线的二维子数组的轴。默认为 `a` 的前两个轴。
    dtype : dtype, optional
        决定返回数组和累加器的数据类型。如果 dtype 为 None 并且 `a` 是整数类型且精度低于默认整数精度,
        则使用默认整数精度。否则,精度与 `a` 相同。
    out : ndarray, optional
        存放输出结果的数组。其类型保持不变,必须具有正确的形状来容纳输出。

    返回
    -------
    sum_along_diagonals : ndarray
        如果 `a` 是二维数组,返回沿对角线的和。如果 `a` 的维度更高,则返回沿对角线的和组成的数组。

    参见
    --------
    diag, diagonal, diagflat

    示例
    --------
    >>> np.trace(np.eye(3))
    3.0
    >>> a = np.arange(8).reshape((2,2,2))
    >>> np.trace(a)
    array([6, 8])

    >>> a = np.arange(24).reshape((2,2,2,3))
    >>> np.trace(a).shape
    (2, 3)

    """
    # 如果 `a` 是 matrix 类型,则通过 asarray 转换为数组再调用 trace 方法获取对角线元素之和,以保持向后兼容性
    if isinstance(a, np.matrix):
        return asarray(a).trace(
            offset=offset, axis1=axis1, axis2=axis2, dtype=dtype, out=out
        )
    else:
        # 否则,将 `a` 转换为数组并调用 trace 方法获取对角线元素之和
        return asanyarray(a).trace(
            offset=offset, axis1=axis1, axis2=axis2, dtype=dtype, out=out
        )


# 定义一个函数 _ravel_dispatcher,用于调度 ravel 函数的参数
def _ravel_dispatcher(a, order=None):
    # 返回元组 (a,),作为 ravel 函数的参数
    return (a,)


# 使用 array_function_dispatch 装饰器定义 ravel 函数
@array_function_dispatch(_ravel_dispatcher)
def ravel(a, order='C'):
    """返回一个连续展平的数组。

    返回一个包含输入元素的一维数组。仅在需要时才会复制。

    从 NumPy 1.10 开始,返回的数组将具有与输入数组相同的类型。
    (例如,对于输入的掩码数组,将返回掩码数组)

    参数
    ----------
    a : array_like
        输入数组,要展平。
    order : {'C', 'F', 'A', 'K'}, optional
        指定数组元素在展平时的顺序(C 表示按行,F 表示按列,A 表示按原顺序,K 表示按内存顺序)。默认为 'C'。

    返回
    -------
    raveled_array : ndarray
        连续展平后的一维数组。

    """
    # 返回使用 asarray 转换的数组的展平结果,以保持向后兼容性
    return asarray(a).ravel(order=order)
    # 定义函数 `ravel`
    def ravel(a, order='C'):
        # 返回输入数组 `a` 的展平版本,按照指定的顺序 `order` 进行展平
        y = a.ravel(order=order)
        # 返回展平后的数组 `y`,保持 `a` 的相同子类型,并且是一个连续的 1-D 数组,形状为 `(a.size,)`
        return y
    # 如果输入的参数 a 是 numpy 矩阵类型,则将其转换为数组类型,并按指定的顺序展平
    if isinstance(a, np.matrix):
        return asarray(a).ravel(order=order)
    else:
        # 如果输入的参数 a 不是 numpy 矩阵类型,则将其转换为任意数组类型,并按指定的顺序展平
        return asanyarray(a).ravel(order=order)
# 定义一个函数 _nonzero_dispatcher,接受一个参数 a,返回包含 a 的元组
def _nonzero_dispatcher(a):
    return (a,)

# 使用 array_function_dispatch 装饰器,将 _nonzero_dispatcher 与 nonzero 函数关联起来
@array_function_dispatch(_nonzero_dispatcher)
# 定义函数 nonzero,返回非零元素的索引
def nonzero(a):
    """
    Return the indices of the elements that are non-zero.

    Returns a tuple of arrays, one for each dimension of `a`,
    containing the indices of the non-zero elements in that
    dimension. The values in `a` are always tested and returned in
    row-major, C-style order.

    To group the indices by element, rather than dimension, use `argwhere`,
    which returns a row for each non-zero element.

    .. note::

       When called on a zero-d array or scalar, ``nonzero(a)`` is treated
       as ``nonzero(atleast_1d(a))``.

       .. deprecated:: 1.17.0

          Use `atleast_1d` explicitly if this behavior is deliberate.

    Parameters
    ----------
    a : array_like
        Input array.

    Returns
    -------
    tuple_of_arrays : tuple
        Indices of elements that are non-zero.

    See Also
    --------
    flatnonzero :
        Return indices that are non-zero in the flattened version of the input
        array.
    ndarray.nonzero :
        Equivalent ndarray method.
    count_nonzero :
        Counts the number of non-zero elements in the input array.

    Notes
    -----
    While the nonzero values can be obtained with ``a[nonzero(a)]``, it is
    recommended to use ``x[x.astype(bool)]`` or ``x[x != 0]`` instead, which
    will correctly handle 0-d arrays.

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

    >>> x[np.nonzero(x)]
    array([3, 4, 5, 6])
    >>> np.transpose(np.nonzero(x))
    array([[0, 0],
           [1, 1],
           [2, 0],
           [2, 1]])

    A common use for ``nonzero`` is to find the indices of an array, where
    a condition is True.  Given an array `a`, the condition `a` > 3 is a
    boolean array and since False is interpreted as 0, np.nonzero(a > 3)
    yields the indices of the `a` where the condition is true.

    >>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    >>> a > 3
    array([[False, False, False],
           [ True,  True,  True],
           [ True,  True,  True]])
    >>> np.nonzero(a > 3)
    (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))

    Using this result to index `a` is equivalent to using the mask directly:

    >>> a[np.nonzero(a > 3)]
    array([4, 5, 6, 7, 8, 9])
    >>> a[a > 3]  # prefer this spelling
    array([4, 5, 6, 7, 8, 9])

    ``nonzero`` can also be called as a method of the array.

    >>> (a > 3).nonzero()
    (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))

    """
    # 调用 _wrapfunc 函数,传入参数 a 和字符串 'nonzero',返回结果
    return _wrapfunc(a, 'nonzero')


# 定义一个函数 _shape_dispatcher,接受一个参数 a,返回包含 a 的元组
def _shape_dispatcher(a):
    return (a,)

# 使用 array_function_dispatch 装饰器,将 _shape_dispatcher 与 shape 函数关联起来
@array_function_dispatch(_shape_dispatcher)
# 定义函数 shape,返回数组的形状
def shape(a):
    """
    Return the shape of an array.

    Parameters
    ----------
    a : array_like
        Input array.

    Returns
    -------
    """
    shape : tuple of ints
        The elements of the shape tuple give the lengths of the
        corresponding array dimensions.

    See Also
    --------
    len : ``len(a)`` is equivalent to ``np.shape(a)[0]`` for N-D arrays with
          ``N>=1``.
    ndarray.shape : Equivalent array method.

    Examples
    --------
    >>> np.shape(np.eye(3))
    (3, 3)
    >>> np.shape([[1, 3]])
    (1, 2)
    >>> np.shape([0])
    (1,)
    >>> np.shape(0)
    ()

    >>> a = np.array([(1, 2), (3, 4), (5, 6)],
    ...              dtype=[('x', 'i4'), ('y', 'i4')])
    >>> np.shape(a)
    (3,)
    >>> a.shape
    (3,)

    """
    try:
        # 尝试获取数组 a 的形状
        result = a.shape
    except AttributeError:
        # 若 a 没有 shape 属性,则将 a 转换为 ndarray 后再获取其形状
        result = asarray(a).shape
    # 返回获取到的形状结果
    return result
# 定义一个函数 _compress_dispatcher,返回一个包含条件、数组及输出的元组
def _compress_dispatcher(condition, a, axis=None, out=None):
    return (condition, a, out)

# 使用 array_function_dispatch 装饰器将 compress 函数与 _compress_dispatcher 函数关联
@array_function_dispatch(_compress_dispatcher)
def compress(condition, a, axis=None, out=None):
    """
    返回数组沿指定轴的选定片段。

    在沿指定轴工作时,对于每个条件为 True 的索引,从 `a` 中返回一个 `output` 切片。
    在处理 1-D 数组时,`compress` 等效于 `extract`。

    参数
    ----------
    condition : 1-D 布尔数组
        选择要返回的条目的数组。如果 len(condition) 小于给定轴上 `a` 的大小,则输出被截断为条件数组的长度。
    a : array_like
        要从中提取部分的数组。
    axis : int, optional
        沿其获取切片的轴。如果为 None(默认),则在展平数组上工作。
    out : ndarray, optional
        输出数组。其类型被保留,必须具有正确的形状以容纳输出。

    返回
    -------
    compressed_array : ndarray
        `a` 的副本,删除了在轴上条件为 False 的切片。

    另请参见
    --------
    take, choose, diag, diagonal, select
    ndarray.compress : 数组中的等效方法
    extract : 在处理 1-D 数组时的等效方法
    :ref:`ufuncs-output-type`

    示例
    --------
    >>> a = np.array([[1, 2], [3, 4], [5, 6]])
    >>> a
    array([[1, 2],
           [3, 4],
           [5, 6]])
    >>> np.compress([0, 1], a, axis=0)
    array([[3, 4]])
    >>> np.compress([False, True, True], a, axis=0)
    array([[3, 4],
           [5, 6]])
    >>> np.compress([False, True], a, axis=1)
    array([[2],
           [4],
           [6]])

    在展平数组上工作不会返回沿轴的切片,而是选择元素。

    >>> np.compress([False, True], a)
    array([2])

    """

# 定义一个函数 _clip_dispatcher,返回一个包含数组、最小值、最大值及输出的元组
def _clip_dispatcher(a, a_min, a_max, out=None, **kwargs):
    return (a, a_min, a_max)

# 使用 array_function_dispatch 装饰器将 clip 函数与 _clip_dispatcher 函数关联
@array_function_dispatch(_clip_dispatcher)
def clip(a, a_min, a_max, out=None, **kwargs):
    """
    对数组中的值进行裁剪(限制)。

    给定一个区间,将超出该区间的值裁剪到区间的边缘。例如,如果指定区间为 ``[0, 1]``,
    小于 0 的值变为 0,大于 1 的值变为 1。

    等效于但比 ``np.minimum(a_max, np.maximum(a, a_min))`` 更快。

    不执行任何检查以确保 ``a_min < a_max``。

    参数
    ----------
    a : array_like
        包含要裁剪元素的数组。
    a_min, a_max : array_like 或 None
        最小值和最大值。如果为 ``None``,则不在相应边缘执行裁剪。`a_min` 和 `a_max` 中只能有一个为 ``None``。两者与 `a` 广播。

    """
    out : ndarray, optional
        结果将被放置在这个数组中。它可以是用于原地裁剪的输入数组。`out` 必须具有正确的形状来容纳输出。其类型将被保留。
    **kwargs
        其他关键字参数,请参阅:ref:`ufunc docs <ufuncs.kwargs>`。

        .. versionadded:: 1.17.0

    Returns
    -------
    clipped_array : ndarray
        元素为 `a` 的数组,但其中小于 `a_min` 的值被替换为 `a_min`,大于 `a_max` 的值被替换为 `a_max`。

    See Also
    --------
    :ref:`ufuncs-output-type`

    Notes
    -----
    当 `a_min` 大于 `a_max` 时,`clip` 返回一个数组,其中所有值都等于 `a_max`,如第二个示例所示。

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

    """
    return _wrapfunc(a, 'clip', a_min, a_max, out=out, **kwargs)
# 定义一个分派函数 `_sum_dispatcher`,用于调度参数 `a`,返回一个元组 `(a, out)`
def _sum_dispatcher(a, axis=None, dtype=None, out=None, keepdims=None,
                    initial=None, where=None):
    return (a, out)

# 装饰器 `array_function_dispatch` 用于将 `_sum_dispatcher` 与函数 `sum` 关联
@array_function_dispatch(_sum_dispatcher)
def sum(a, axis=None, dtype=None, out=None, keepdims=np._NoValue,
        initial=np._NoValue, where=np._NoValue):
    """
    Sum of array elements over a given axis.

    Parameters
    ----------
    a : array_like
        Elements to sum.
    axis : None or int or tuple of ints, optional
        Axis or axes along which a sum is performed.  The default,
        axis=None, will sum all of the elements of the input array.  If
        axis is negative it counts from the last to the first axis.

        .. versionadded:: 1.7.0

        If axis is a tuple of ints, a sum is performed on all of the axes
        specified in the tuple instead of a single axis or all the axes as
        before.
    dtype : dtype, optional
        The type of the returned array and of the accumulator in which the
        elements are summed.  The dtype of `a` is used by default unless `a`
        has an integer dtype of less precision than the default platform
        integer.  In that case, if `a` is signed then the platform integer
        is used while if `a` is unsigned then an unsigned integer of the
        same precision as the platform integer is used.
    out : ndarray, optional
        Alternative output array in which to place the result. It must have
        the same shape as the expected output, but the type of the output
        values will be cast if necessary.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the input array.

        If the default value is passed, then `keepdims` will not be
        passed through to the `sum` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.
    initial : scalar, optional
        Starting value for the sum. See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.15.0

    where : array_like of bool, optional
        Elements to include in the sum. See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.17.0

    Returns
    -------
    sum_along_axis : ndarray
        An array with the same shape as `a`, with the specified
        axis removed.   If `a` is a 0-d array, or if `axis` is None, a scalar
        is returned.  If an output array is specified, a reference to
        `out` is returned.

    See Also
    --------
    ndarray.sum : Equivalent method.
    add: ``numpy.add.reduce`` equivalent function.
    cumsum : Cumulative sum of array elements.
    trapezoid : Integration of array values using composite trapezoidal rule.

    mean, average

    Notes
    -----
    """
    # 函数 `sum` 实现了对数组元素沿指定轴的求和操作
    # 具体参数解释详见上方的 docstring 文档
    pass  # 这里是函数体的占位符,实际上没有实现其他功能
    if isinstance(a, _gentype):
        # 如果参数 a 是 _gentype 类型的实例
        warnings.warn(
            # 发出警告,提示调用 np.sum(generator) 已被弃用,并且未来会产生不同的结果。
            # 建议使用 np.sum(np.fromiter(generator)) 或者 Python 的内置 sum 函数代替。
            "Calling np.sum(generator) is deprecated, and in the future will "
            "give a different result. Use np.sum(np.fromiter(generator)) or "
            "the python sum builtin instead.",
            DeprecationWarning, stacklevel=2
        )

        # 使用 _sum_ 函数对参数 a 进行求和
        res = _sum_(a)
        if out is not None:
            # 如果指定了输出数组 out,则将结果 res 复制给 out
            out[...] = res
            return out
        # 如果没有指定输出数组 out,则直接返回结果 res
        return res

    # 调用 _wrapreduction 函数进行归约操作
    return _wrapreduction(
        a, np.add, 'sum', axis, dtype, out,
        keepdims=keepdims, initial=initial, where=where
    )
# 定义了一个私有函数 `_any_dispatcher`,用于分发参数 `a`, `axis`, `out`, `keepdims`, `where` 到元组中
def _any_dispatcher(a, axis=None, out=None, keepdims=None, *, where=np._NoValue):
    # 返回元组 `(a, where, out)`,将输入参数 `a`, `where`, `out` 打包成元组返回
    return (a, where, out)

# 使用装饰器 `array_function_dispatch` 装饰的函数 `any`,用于测试数组在指定轴向上是否有任意元素为 `True`
@array_function_dispatch(_any_dispatcher)
def any(a, axis=None, out=None, keepdims=np._NoValue, *, where=np._NoValue):
    """
    Test whether any array element along a given axis evaluates to True.

    Returns single boolean if `axis` is ``None``

    Parameters
    ----------
    a : array_like
        Input array or object that can be converted to an array.
    axis : None or int or tuple of ints, optional
        Axis or axes along which a logical OR reduction is performed.
        The default (``axis=None``) is to perform a logical OR over all
        the dimensions of the input array. `axis` may be negative, in
        which case it counts from the last to the first axis.

        .. versionadded:: 1.7.0

        If this is a tuple of ints, a reduction is performed on multiple
        axes, instead of a single axis or all the axes as before.
    out : ndarray, optional
        Alternate output array in which to place the result.  It must have
        the same shape as the expected output and its type is preserved
        (e.g., if it is of type float, then it will remain so, returning
        1.0 for True and 0.0 for False, regardless of the type of `a`).
        See :ref:`ufuncs-output-type` for more details.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the input array.

        If the default value is passed, then `keepdims` will not be
        passed through to the `any` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.
    where : array_like of bool, optional
        Elements to include in checking for any `True` values.
        See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.20.0

    Returns
    -------
    any : bool or ndarray
        A new boolean or `ndarray` is returned unless `out` is specified,
        in which case a reference to `out` is returned.

    See Also
    --------
    ndarray.any : equivalent method

    all : Test whether all elements along a given axis evaluate to True.

    Notes
    -----
    Not a Number (NaN), positive infinity and negative infinity evaluate
    to `True` because these are not equal to zero.

    .. versionchanged:: 2.0
       Before NumPy 2.0, ``any`` did not return booleans for object dtype
       input arrays.
       This behavior is still available via ``np.logical_or.reduce``.

    Examples
    --------
    >>> np.any([[True, False], [True, True]])
    True

    >>> np.any([[True,  False, True ],
    ...         [False, False, False]], axis=0)
    array([ True, False, True])

    >>> np.any([-1, 0, 5])
    True
    """
    >>> np.any([[np.nan], [np.inf]], axis=1, keepdims=True)
    array([[ True],
           [ True]])

# 在给定的二维数组中,沿着指定的轴(axis=1,即按行)检查是否存在任何非零元素。
# 返回一个布尔数组,表示每行中是否至少存在一个非零元素。

    >>> np.any([[True, False], [False, False]], where=[[False], [True]])
    False

# 在给定的二维数组中,使用where参数指定条件,检查是否存在任何非零元素。
# 返回False,因为第一行的where条件为False,第二行无非零元素。

    >>> a = np.array([[1, 0, 0],
    ...               [0, 0, 1],
    ...               [0, 0, 0]])
    >>> np.any(a, axis=0)
    array([ True, False,  True])
    >>> np.any(a, axis=1)
    array([ True,  True, False])

# 创建一个3x3的NumPy数组a,表示一个稀疏的矩阵。
# np.any(a, axis=0) 沿着列轴(axis=0)检查数组a中是否存在任何非零元素。
# 返回一个布尔数组,每个元素表示对应列中是否至少存在一个非零元素。
# np.any(a, axis=1) 沿着行轴(axis=1)检查数组a中是否存在任何非零元素。
# 返回一个布尔数组,每个元素表示对应行中是否至少存在一个非零元素。

    >>> o=np.array(False)
    >>> z=np.any([-1, 4, 5], out=o)
    >>> z, o
    (array(True), array(True))

# 创建一个布尔数组o,初始值为False。
# 使用np.any函数检查[-1, 4, 5]数组中是否存在任何非零元素,并将结果存储在z变量中,同时更新布尔数组o。
# 返回z为True(因为数组中有非零元素),o也为True。

    >>> # Check now that z is a reference to o
    >>> z is o
    True

# 检查变量z和o是否引用了相同的对象(即它们是否是同一个对象)。
# 返回True,表明z和o指向同一个布尔数组对象。

    >>> id(z), id(o) # identity of z and o              # doctest: +SKIP
    (191614240, 191614240)

# 获取变量z和o的内存地址。
# 返回它们的内存地址,这里的具体地址数字可能会因为环境不同而有所变化。
# (注:由于文档测试模式被跳过,这段代码不会在文档测试中执行。)

    """
    return _wrapreduction_any_all(a, np.logical_or, 'any', axis, out,
                                  keepdims=keepdims, where=where)

# 返回调用_wrapreduction_any_all函数的结果,该函数用于对数组a进行逻辑或(logical_or)操作,
# 在指定轴上检查是否有任何元素满足条件,可指定输出out、保持维度keepdims和where条件。
# 定义一个调度器函数,用于决定如何分派参数 `a`, `axis`, `out`, `keepdims`, `where`
def _all_dispatcher(a, axis=None, out=None, keepdims=None, *, where=None):
    # 返回参数 `a`, `where`, `out` 的元组
    return (a, where, out)


# 使用 array_function_dispatch 装饰器将 _all_dispatcher 函数与 all 函数关联起来
@array_function_dispatch(_all_dispatcher)
def all(a, axis=None, out=None, keepdims=np._NoValue, *, where=np._NoValue):
    """
    Test whether all array elements along a given axis evaluate to True.

    Parameters
    ----------
    a : array_like
        Input array or object that can be converted to an array.
    axis : None or int or tuple of ints, optional
        Axis or axes along which a logical AND reduction is performed.
        The default (``axis=None``) is to perform a logical AND over all
        the dimensions of the input array. `axis` may be negative, in
        which case it counts from the last to the first axis.

        .. versionadded:: 1.7.0

        If this is a tuple of ints, a reduction is performed on multiple
        axes, instead of a single axis or all the axes as before.
    out : ndarray, optional
        Alternate output array in which to place the result.
        It must have the same shape as the expected output and its
        type is preserved (e.g., if ``dtype(out)`` is float, the result
        will consist of 0.0's and 1.0's). See :ref:`ufuncs-output-type`
        for more details.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the input array.

        If the default value is passed, then `keepdims` will not be
        passed through to the `all` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.
    where : array_like of bool, optional
        Elements to include in checking for all `True` values.
        See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.20.0

    Returns
    -------
    all : ndarray, bool
        A new boolean or array is returned unless `out` is specified,
        in which case a reference to `out` is returned.

    See Also
    --------
    ndarray.all : equivalent method

    any : Test whether any element along a given axis evaluates to True.

    Notes
    -----
    Not a Number (NaN), positive infinity and negative infinity
    evaluate to `True` because these are not equal to zero.

    .. versionchanged:: 2.0
       Before NumPy 2.0, ``all`` did not return booleans for object dtype
       input arrays.
       This behavior is still available via ``np.logical_and.reduce``.

    Examples
    --------
    >>> np.all([[True,False],[True,True]])
    False

    >>> np.all([[True,False],[True,True]], axis=0)
    array([ True, False])

    >>> np.all([-1, 4, 5])
    True

    >>> np.all([1.0, np.nan])
    True

    >>> np.all([[True, True], [False, True]], where=[[True], [False]])
    True

    >>> o=np.array(False)
    """
    # 函数体中不需要添加额外的注释,因为文档字符串已经充分解释了函数的功能和用法
    # 调用 NumPy 的 all 函数,检查数组中所有元素是否都为真
    >>> z=np.all([-1, 4, 5], out=o)
    # 获取 z 和 o 对象的内存地址,并输出 z 的值
    >>> id(z), id(o), z
    # 输出结果显示 z 和 o 对象的内存地址以及 z 的值为数组中所有元素是否都为真的结果
    (28293632, 28293632, array(True)) # may vary
    
    """
    # 返回调用 _wrapreduction_any_all 函数的结果,执行数组的逻辑与操作,用于 'all' 操作
    return _wrapreduction_any_all(a, np.logical_and, 'all', axis, out,
                                  keepdims=keepdims, where=where)
# 定义一个分派器函数,用于 `cumsum` 函数,将传入的参数 `a`、`axis`、`dtype` 和 `out` 包装成元组返回
def _cumsum_dispatcher(a, axis=None, dtype=None, out=None):
    return (a, out)


# 使用 `array_function_dispatch` 装饰器标记的 `cumsum` 函数,实现了累积求和操作
@array_function_dispatch(_cumsum_dispatcher)
def cumsum(a, axis=None, dtype=None, out=None):
    """
    Return the cumulative sum of the elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input array.
    axis : int, optional
        Axis along which the cumulative sum is computed. The default
        (None) is to compute the cumsum over the flattened array.
    dtype : dtype, optional
        Type of the returned array and of the accumulator in which the
        elements are summed.  If `dtype` is not specified, it defaults
        to the dtype of `a`, unless `a` has an integer dtype with a
        precision less than that of the default platform integer.  In
        that case, the default platform integer is used.
    out : ndarray, optional
        Alternative output array in which to place the result. It must
        have the same shape and buffer length as the expected output
        but the type will be cast if necessary. See :ref:`ufuncs-output-type`
        for more details.

    Returns
    -------
    cumsum_along_axis : ndarray.
        A new array holding the result is returned unless `out` is
        specified, in which case a reference to `out` is returned. The
        result has the same size as `a`, and the same shape as `a` if
        `axis` is not None or `a` is a 1-d array.

    See Also
    --------
    sum : Sum array elements.
    trapezoid : Integration of array values using composite trapezoidal rule.
    diff : Calculate the n-th discrete difference along given axis.

    Notes
    -----
    Arithmetic is modular when using integer types, and no error is
    raised on overflow.

    ``cumsum(a)[-1]`` may not be equal to ``sum(a)`` for floating-point
    values since ``sum`` may use a pairwise summation routine, reducing
    the roundoff-error. See `sum` for more information.

    Examples
    --------
    >>> a = np.array([[1,2,3], [4,5,6]])
    >>> a
    array([[1, 2, 3],
           [4, 5, 6]])
    >>> np.cumsum(a)
    array([ 1,  3,  6, 10, 15, 21])
    >>> np.cumsum(a, dtype=float)     # specifies type of output value(s)
    array([  1.,   3.,   6.,  10.,  15.,  21.])

    >>> np.cumsum(a,axis=0)      # sum over rows for each of the 3 columns
    array([[1, 2, 3],
           [5, 7, 9]])
    >>> np.cumsum(a,axis=1)      # sum over columns for each of the 2 rows
    array([[ 1,  3,  6],
           [ 4,  9, 15]])

    ``cumsum(b)[-1]`` may not be equal to ``sum(b)``

    >>> b = np.array([1, 2e-9, 3e-9] * 1000000)
    >>> b.cumsum()[-1]
    1000000.0050045159
    >>> b.sum()
    1000000.0050000029

    """
    # 调用 `_wrapfunc` 函数,传递参数 `a`, 'cumsum', `axis`, `dtype`, `out`,并返回其结果
    return _wrapfunc(a, 'cumsum', axis=axis, dtype=dtype, out=out)


# 定义一个分派器函数,用于 `ptp` 函数,将传入的参数 `a`, `axis`, `out`, `keepdims` 包装成元组返回
def _ptp_dispatcher(a, axis=None, out=None, keepdims=None):
    return (a, out)


# 使用 `array_function_dispatch` 装饰器标记的 `ptp` 函数,封装了计算数组中元素沿指定轴的峰值到峰值的范围的操作
@array_function_dispatch(_ptp_dispatcher)
def ptp(a, axis=None, out=None, keepdims=np._NoValue):
    """
    # 创建一个空字典用于存储参数
    kwargs = {}
    # 如果 keepdims 参数不是默认值 np._NoValue,则将其加入 kwargs 字典中
    if keepdims is not np._NoValue:
        kwargs['keepdims'] = keepdims
    # 调用底层的 _ptp 方法来计算给定数组的峰值到峰值范围
    return _methods._ptp(a, axis=axis, out=out, **kwargs)
# 定义一个分发器函数 `_max_dispatcher`,用于选择正确的输入参数和输出参数
def _max_dispatcher(a, axis=None, out=None, keepdims=None, initial=None,
                    where=None):
    # 返回输入数组 `a` 和输出数组 `out`
    return (a, out)

# 使用 `array_function_dispatch` 装饰器注册 `_max_dispatcher` 函数
# 设置模块为 `numpy`
@array_function_dispatch(_max_dispatcher)
@set_module('numpy')
# 定义 `max` 函数,计算数组或沿着指定轴的最大值
def max(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue,
        where=np._NoValue):
    """
    Return the maximum of an array or maximum along an axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which to operate.  By default, flattened input is
        used.

        .. versionadded:: 1.7.0

        If this is a tuple of ints, the maximum is selected over multiple axes,
        instead of a single axis or all the axes as before.
    out : ndarray, optional
        Alternative output array in which to place the result.  Must
        be of the same shape and buffer length as the expected output.
        See :ref:`ufuncs-output-type` for more details.

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

        If the default value is passed, then `keepdims` will not be
        passed through to the ``max`` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.

    initial : scalar, optional
        The minimum value of an output element. Must be present to allow
        computation on empty slice. See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.15.0

    where : array_like of bool, optional
        Elements to compare for the maximum. See `~numpy.ufunc.reduce`
        for details.

        .. versionadded:: 1.17.0

    Returns
    -------
    max : ndarray or scalar
        Maximum of `a`. If `axis` is None, the result is a scalar value.
        If `axis` is an int, the result is an array of dimension
        ``a.ndim - 1``. If `axis` is a tuple, the result is an array of
        dimension ``a.ndim - len(axis)``.

    See Also
    --------
    amin :
        The minimum value of an array along a given axis, propagating any NaNs.
    nanmax :
        The maximum value of an array along a given axis, ignoring any NaNs.
    maximum :
        Element-wise maximum of two arrays, propagating any NaNs.
    fmax :
        Element-wise maximum of two arrays, ignoring any NaNs.
    argmax :
        Return the indices of the maximum values.

    nanmin, minimum, fmin

    Notes
    -----
    NaN values are propagated, that is if at least one item is NaN, the
    corresponding max value will be NaN as well. To ignore NaN values
    (MATLAB behavior), please use nanmax.

    Don't use `~numpy.max` for element-wise comparison of 2 arrays; when
    ``a.shape[0]`` is 2, ``maximum(a[0], a[1])`` is faster than
    """
    # 函数文档字符串描述了 `max` 函数的输入参数和返回值
    # 返回数组 `a` 沿指定轴的最大值。
    
    return _wrapreduction(a, np.maximum, 'max', axis, None, out,
                          keepdims=keepdims, initial=initial, where=where)
    
    
    这段代码是 NumPy 中的 `np.max` 函数的核心实现。它调用了 `_wrapreduction` 函数,用于执行数组 `a` 的归约操作,具体功能包括:
    
    - `a`: 要计算最大值的输入数组。
    - `np.maximum`: 归约函数,用于比较两个元素并返回较大值的函数。
    - `'max'`: 字符串标识,表示进行最大值计算。
    - `axis`: 指定的轴,沿着该轴计算最大值。
    - `None`: 在此处没有使用。
    - `out`: 可选的输出数组,用于存放结果。
    - `keepdims`: 布尔值,指示是否保持归约操作后的维度。
    - `initial`: 可选的初始值,在进行归约操作时使用,用于处理空切片或特定条件下的最大值计算。
    - `where`: 可选的条件数组,用于指定进行归约操作的元素范围。
    
    这段代码对应的注释简明扼要地描述了函数的参数和功能,确保了读者能够快速理解代码的作用和用法。
@array_function_dispatch(_max_dispatcher)
def amax(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue,
         where=np._NoValue):
    """
    Return the maximum of an array or maximum along an axis.

    `amax` is an alias of `~numpy.max`.

    See Also
    --------
    max : alias of this function
    ndarray.max : equivalent method
    """
    # 使用 _wrapreduction 函数对数组进行约简操作,使用 np.maximum 函数找到数组的最大值
    return _wrapreduction(a, np.maximum, 'max', axis, None, out,
                          keepdims=keepdims, initial=initial, where=where)


def _min_dispatcher(a, axis=None, out=None, keepdims=None, initial=None,
                    where=None):
    # 返回输入参数 a 和 out
    return (a, out)


@array_function_dispatch(_min_dispatcher)
def min(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue,
        where=np._NoValue):
    """
    Return the minimum of an array or minimum along an axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which to operate.  By default, flattened input is
        used.

        .. versionadded:: 1.7.0

        If this is a tuple of ints, the minimum is selected over multiple axes,
        instead of a single axis or all the axes as before.
    out : ndarray, optional
        Alternative output array in which to place the result.  Must
        be of the same shape and buffer length as the expected output.
        See :ref:`ufuncs-output-type` for more details.

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

        If the default value is passed, then `keepdims` will not be
        passed through to the ``min`` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.

    initial : scalar, optional
        The maximum value of an output element. Must be present to allow
        computation on empty slice. See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.15.0

    where : array_like of bool, optional
        Elements to compare for the minimum. See `~numpy.ufunc.reduce`
        for details.

        .. versionadded:: 1.17.0

    Returns
    -------
    min : ndarray or scalar
        Minimum of `a`. If `axis` is None, the result is a scalar value.
        If `axis` is an int, the result is an array of dimension
        ``a.ndim - 1``.  If `axis` is a tuple, the result is an array of
        dimension ``a.ndim - len(axis)``.

    See Also
    --------
    amax :
        The maximum value of an array along a given axis, propagating any NaNs.
    nanmin :
        The minimum value of an array along a given axis, ignoring any NaNs.
    minimum :
        Element-wise minimum of two arrays, propagating any NaNs.
    """
    # 使用 _wrapreduction 函数对数组进行约简操作,使用 np.minimum 函数找到数组的最小值
    return _wrapreduction(a, np.minimum, 'min', axis, None, out,
                          keepdims=keepdims, initial=initial, where=where)
    fmin :
        # 计算两个数组的逐元素最小值,忽略任何 NaN 值。
    argmin :
        # 返回最小值的索引数组。

    nanmax, maximum, fmax

    Notes
    -----
    # NaN 值会被传播,即如果至少有一个元素是 NaN,则对应的最小值也将是 NaN。要忽略 NaN 值(类似 MATLAB 的行为),请使用 nanmin。

    Don't use `~numpy.min` for element-wise comparison of 2 arrays; when
    ``a.shape[0]`` is 2, ``minimum(a[0], a[1])`` is faster than
    ``min(a, axis=0)``.
    # 不要使用 `~numpy.min` 进行两个数组的逐元素比较;当 ``a.shape[0]`` 为 2 时,``minimum(a[0], a[1])`` 比 ``min(a, axis=0)`` 更快。

    Examples
    --------
    >>> a = np.arange(4).reshape((2,2))
    >>> a
    array([[0, 1],
           [2, 3]])
    >>> np.min(a)           # Minimum of the flattened array
    0
    # 扁平化数组的最小值
    >>> np.min(a, axis=0)   # Minima along the first axis
    array([0, 1])
    # 沿第一个轴的最小值
    >>> np.min(a, axis=1)   # Minima along the second axis
    array([0, 2])
    # 沿第二个轴的最小值
    >>> np.min(a, where=[False, True], initial=10, axis=0)
    array([10,  1])
    # 在指定条件下沿第零轴的最小值

    >>> b = np.arange(5, dtype=float)
    >>> b[2] = np.nan
    >>> np.min(b)
    np.float64(nan)
    # 返回数组中的最小值,包括 NaN 值
    >>> np.min(b, where=~np.isnan(b), initial=10)
    0.0
    # 在忽略 NaN 值的情况下返回数组中的最小值
    >>> np.nanmin(b)
    0.0
    # 返回数组中的最小值,忽略 NaN 值

    >>> np.min([[-50], [10]], axis=-1, initial=0)
    array([-50,   0])
    # 沿最后一个轴的最小值,指定初始值为 0

    Notice that the initial value is used as one of the elements for which the
    minimum is determined, unlike for the default argument Python's max
    function, which is only used for empty iterables.
    # 注意,初始值将作为决定最小值的元素之一,与 Python 的 max 函数默认参数不同,后者仅用于空可迭代对象。

    Notice that this isn't the same as Python's ``default`` argument.
    # 请注意,这与 Python 的 ``default`` 参数不同。

    >>> np.min([6], initial=5)
    5
    # 返回数组的最小值,指定初始值为 5
    >>> min([6], default=5)
    6
    # 返回数组的最小值,使用默认参数 5
    """
    return _wrapreduction(a, np.minimum, 'min', axis, None, out,
                          keepdims=keepdims, initial=initial, where=where)
    # 调用内部函数 _wrapreduction,使用 np.minimum 函数计算数组 a 沿指定轴的最小值,并返回结果
# 使用装饰器 `_min_dispatcher` 将该函数注册为 `amin` 的分派函数
@array_function_dispatch(_min_dispatcher)
# 定义函数 `amin`,返回数组或沿着指定轴的最小值
def amin(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue,
         where=np._NoValue):
    """
    Return the minimum of an array or minimum along an axis.

    `amin` is an alias of `~numpy.min`.

    See Also
    --------
    min : alias of this function
    ndarray.min : equivalent method
    """
    # 调用 `_wrapreduction` 函数,对数组进行最小值规约操作
    return _wrapreduction(a, np.minimum, 'min', axis, None, out,
                          keepdims=keepdims, initial=initial, where=where)


# 使用 `_prod_dispatcher` 装饰器将该函数注册为 `prod` 的分派函数
@array_function_dispatch(_prod_dispatcher)
# 定义函数 `prod`,返回沿指定轴的数组元素的乘积
def prod(a, axis=None, dtype=None, out=None, keepdims=np._NoValue,
         initial=np._NoValue, where=np._NoValue):
    """
    Return the product of array elements over a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which a product is performed.  The default,
        axis=None, will calculate the product of all the elements in the
        input array. If axis is negative it counts from the last to the
        first axis.

        .. versionadded:: 1.7.0

        If axis is a tuple of ints, a product is performed on all of the
        axes specified in the tuple instead of a single axis or all the
        axes as before.
    dtype : dtype, optional
        The type of the returned array, as well as of the accumulator in
        which the elements are multiplied.  The dtype of `a` is used by
        default unless `a` has an integer dtype of less precision than the
        default platform integer.  In that case, if `a` is signed then the
        platform integer is used while if `a` is unsigned then an unsigned
        integer of the same precision as the platform integer is used.
    out : ndarray, optional
        Alternative output array in which to place the result. It must have
        the same shape as the expected output, but the type of the output
        values will be cast if necessary.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left in the
        result as dimensions with size one. With this option, the result
        will broadcast correctly against the input array.

        If the default value is passed, then `keepdims` will not be
        passed through to the `prod` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.
    initial : scalar, optional
        The starting value for this product. See `~numpy.ufunc.reduce`
        for details.

        .. versionadded:: 1.15.0

    where : array_like of bool, optional
        Elements to include in the product. See `~numpy.ufunc.reduce`
        for details.

        .. versionadded:: 1.17.0

    Returns
    -------
    product_along_axis : ndarray, see `dtype` parameter above.
        An array shaped as `a` but with the specified axis removed.
        Returns a reference to `out` if specified.

    See Also
    --------
    ndarray.prod : equivalent method
    :ref:`ufuncs-output-type`

    Notes
    -----
    Arithmetic is modular when using integer types, and no error is
    raised on overflow.  That means that, on a 32-bit platform:

    >>> x = np.array([536870910, 536870910, 536870910, 536870910])
    >>> np.prod(x)
    16 # may vary

    The product of an empty array is the neutral element 1:

    >>> np.prod([])
    1.0

    Examples
    --------
    By default, calculate the product of all elements:

    >>> np.prod([1.,2.])
    2.0

    Even when the input array is two-dimensional:

    >>> a = np.array([[1., 2.], [3., 4.]])
    >>> np.prod(a)
    24.0

    But we can also specify the axis over which to multiply:

    >>> np.prod(a, axis=1)
    array([  2.,  12.])
    >>> np.prod(a, axis=0)
    array([3., 8.])

    Or select specific elements to include:

    >>> np.prod([1., np.nan, 3.], where=[True, False, True])
    3.0

    If the type of `x` is unsigned, then the output type is
    the unsigned platform integer:

    >>> x = np.array([1, 2, 3], dtype=np.uint8)
    >>> np.prod(x).dtype == np.uint
    True

    If `x` is of a signed integer type, then the output type
    is the default platform integer:

    >>> x = np.array([1, 2, 3], dtype=np.int8)
    >>> np.prod(x).dtype == int
    True

    You can also start the product with a value other than one:

    >>> np.prod([1, 2], initial=5)
    10
    """
    return _wrapreduction(a, np.multiply, 'prod', axis, dtype, out,
                          keepdims=keepdims, initial=initial, where=where)


注释:


# 返回一个沿指定轴删除后的数组,其形状与输入数组 `a` 相同。如果指定了 `out`,则返回其引用。
# 定义一个分发器函数,返回输入参数和输出参数元组
def _cumprod_dispatcher(a, axis=None, dtype=None, out=None):
    return (a, out)


# 使用 array_function_dispatch 装饰器将 cumprod 函数与 _cumprod_dispatcher 分发器关联起来
@array_function_dispatch(_cumprod_dispatcher)
# 定义 cumprod 函数,计算沿指定轴的累积乘积
def cumprod(a, axis=None, dtype=None, out=None):
    """
    返回沿给定轴的元素的累积乘积。

    参数
    ----------
    a : array_like
        输入数组。
    axis : int, optional
        计算累积乘积的轴。默认情况下会展平输入。
    dtype : dtype, optional
        返回数组的类型,以及元素相乘时累加器的类型。如果未指定 *dtype*,则默认为 `a` 的 dtype,
        除非 `a` 具有低于默认平台整数精度的整数 dtype。在这种情况下,将使用默认平台整数。
    out : ndarray, optional
        替代输出数组,用于放置结果。它必须具有与预期输出相同的形状和缓冲区长度,但如果需要会强制转换结果值的类型。

    返回
    -------
    cumprod : ndarray
        返回一个新数组,其中包含结果,除非指定了 `out`,在这种情况下将返回对 `out` 的引用。
    """
    # 调用 _wrapfunc 函数,执行实际的累积乘积计算
    return _wrapfunc(a, 'cumprod', axis=axis, dtype=dtype, out=out)


# 定义一个分发器函数,返回输入参数元组
def _ndim_dispatcher(a):
    return (a,)


# 使用 array_function_dispatch 装饰器将 ndim 函数与 _ndim_dispatcher 分发器关联起来
@array_function_dispatch(_ndim_dispatcher)
# 定义 ndim 函数,返回数组的维数
def ndim(a):
    """
    返回数组的维数。

    参数
    ----------
    a : array_like
        输入数组。如果它还不是 ndarray,则尝试进行转换。

    返回
    -------
    number_of_dimensions : int
        `a` 的维数。标量为零维。

    示例
    --------
    >>> np.ndim([[1,2,3],[4,5,6]])
    2
    >>> np.ndim(np.array([[1,2,3],[4,5,6]]))
    2
    >>> np.ndim(1)
    0
    """
    try:
        # 尝试返回 a 的维数属性
        return a.ndim
    except AttributeError:
        # 如果 a 没有 ndim 属性,则将其转换为 ndarray 并返回其维数
        return asarray(a).ndim
    # 返回一个包含单个元素 a 的元组
    return (a,)
# 使用装饰器进行函数分派,将_size_dispatcher作为分派函数
@array_function_dispatch(_size_dispatcher)
def size(a, axis=None):
    """
    Return the number of elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : int, optional
        Axis along which the elements are counted.  By default, give
        the total number of elements.

    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,1)
    3
    >>> np.size(a,0)
    2

    """
    # 如果axis为None,返回数组a的元素总数
    if axis is None:
        try:
            return a.size
        except AttributeError:
            return asarray(a).size
    else:
        # 返回数组a在指定轴上的元素数
        try:
            return a.shape[axis]
        except AttributeError:
            return asarray(a).shape[axis]


# 使用装饰器进行函数分派,将_round_dispatcher作为分派函数
def _round_dispatcher(a, decimals=None, out=None):
    return (a, out)

@array_function_dispatch(_round_dispatcher)
def round(a, decimals=0, out=None):
    """
    Evenly round to the given number of decimals.

    Parameters
    ----------
    a : array_like
        Input data.
    decimals : int, optional
        Number of decimal places to round to (default: 0).  If
        decimals is negative, it specifies the number of positions to
        the left of the decimal point.
    out : ndarray, optional
        Alternative output array in which to place the result. It must have
        the same shape as the expected output, but the type of the output
        values will be cast if necessary. See :ref:`ufuncs-output-type`
        for more details.

    Returns
    -------
    rounded_array : ndarray
        An array of the same type as `a`, containing the rounded values.
        Unless `out` was specified, a new array is created.  A reference to
        the result is returned.

        The real and imaginary parts of complex numbers are rounded
        separately.  The result of rounding a float is a float.

    See Also
    --------
    ndarray.round : equivalent method
    around : an alias for this function
    ceil, fix, floor, rint, trunc


    Notes
    -----
    For values exactly halfway between rounded decimal values, NumPy
    rounds to the nearest even value. Thus 1.5 and 2.5 round to 2.0,
    -0.5 and 0.5 round to 0.0, etc.

    ``np.round`` uses a fast but sometimes inexact algorithm to round
    floating-point datatypes. For positive `decimals` it is equivalent to
    ``np.true_divide(np.rint(a * 10**decimals), 10**decimals)``, which has
    error due to the inexact representation of decimal fractions in the IEEE
    floating point standard [1]_ and errors introduced when scaling by powers
    of ten. For instance, note the extra "1" in the following:

        >>> np.round(56294995342131.5, 3)
        56294995342131.51


    """
    # 将输入数据a按指定小数位数decimals进行四舍五入
    # 将结果存储在输出数组out中,如果未指定out,则创建新数组
    # 返回与a相同类型的数组,包含四舍五入后的值的引用
    return np.around(a, decimals=decimals, out=out)
    # 使用 `_wrapfunc` 函数将输入数组 `a` 中的每个元素进行四舍五入处理,返回处理后的结果。
    def _round(a, decimals=0, out=None):
        # 调用 `_wrapfunc` 函数,将 `a` 数组中的元素进行四舍五入处理,指定小数位数为 `decimals`,输出到 `out` 中。
        return _wrapfunc(a, 'round', decimals=decimals, out=out)
# 使用装饰器将该函数注册为数组函数分发器,并指定调度器为 _round_dispatcher
@array_function_dispatch(_round_dispatcher)
def around(a, decimals=0, out=None):
    """
    Round an array to the given number of decimals.

    `around` is an alias of `~numpy.round`.

    See Also
    --------
    ndarray.round : equivalent method
    round : alias for this function
    ceil, fix, floor, rint, trunc

    """
    # 调用 _wrapfunc 函数,将 'round' 方法应用于数组 a,指定小数位数为 decimals,输出结果存储在 out 中
    return _wrapfunc(a, 'round', decimals=decimals, out=out)


# 定义 _mean_dispatcher 函数,用于分发计算均值的请求
def _mean_dispatcher(a, axis=None, dtype=None, out=None, keepdims=None, *,
                     where=None):
    return (a, where, out)


# 使用装饰器将 mean 函数注册为数组函数分发器,并指定调度器为 _mean_dispatcher
@array_function_dispatch(_mean_dispatcher)
def mean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue, *,
         where=np._NoValue):
    """
    Compute the arithmetic mean along the specified axis.

    Returns the average of the array elements.  The average is taken over
    the flattened array by default, otherwise over the specified axis.
    `float64` intermediate and return values are used for integer inputs.

    Parameters
    ----------
    a : array_like
        Array containing numbers whose mean is desired. If `a` is not an
        array, a conversion is attempted.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the means are computed. The default is to
        compute the mean of the flattened array.

        .. versionadded:: 1.7.0

        If this is a tuple of ints, a mean is performed over multiple axes,
        instead of a single axis or all the axes as before.
    dtype : data-type, optional
        Type to use in computing the mean.  For integer inputs, the default
        is `float64`; for floating point inputs, it is the same as the
        input dtype.
    out : ndarray, optional
        Alternate output array in which to place the result.  The default
        is ``None``; if provided, it must have the same shape as the
        expected output, but the type will be cast if necessary.
        See :ref:`ufuncs-output-type` for more details.
        See :ref:`ufuncs-output-type` for more details.

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

        If the default value is passed, then `keepdims` will not be
        passed through to the `mean` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.

    where : array_like of bool, optional
        Elements to include in the mean. See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.20.0

    Returns
    -------
    m : ndarray, see dtype parameter above
        If `out=None`, returns a new array containing the mean values,
        otherwise a reference to the output array is returned.

    See Also
    --------
    average : Weighted average
    std, var, nanmean, nanstd, nanvar

    """
    # 调用 _wrapfunc 函数,将 'mean' 方法应用于数组 a,指定轴 axis、数据类型 dtype、输出 out、keepdims 和 where 参数
    return _wrapfunc(a, 'mean', axis=axis, dtype=dtype, out=out, keepdims=keepdims, where=where)
    """
    Calculate the mean along a specified axis of an array `a`, considering optional parameters.
    
    Parameters
    ----------
    a : array_like
        Input array to compute the mean.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the means are computed. The default is to compute
        the mean of the flattened array.
    dtype : data-type, optional
        Type to use in computing the mean. For integer inputs, the default is
        `float64`; for floating-point inputs, it is the same as the input dtype.
    out : ndarray, optional
        Alternate output array in which to place the result. The default is `None`;
        if provided, it must have the same shape as the expected output, but the
        type will be cast if necessary.
    keepdims : bool, optional
        If this is set to `True`, the axes which are reduced are left in the result
        as dimensions with size one.
    where : array_like of bool, optional
        Elements to include in the mean calculation. Only elements that correspond
        to `True` in this boolean mask are included. If `where` is `None`, then all
        elements are included by default.
    
    Returns
    -------
    mean : ndarray
        If `a` is not a masked array, returns the mean of the array elements. If
        `a` is a masked array, returns the mean of the non-masked elements.
        The output data type depends on the input data type and the precision of
        the mean calculation.
    
    Raises
    ------
    TypeError
        If the input `a` is not an ndarray.
    
    See Also
    --------
    average : Weighted average.
    
    Notes
    -----
    The arithmetic mean is the sum of the elements along the axis divided
    by the number of elements.
    
    Note that for floating-point input, the mean is computed using the
    same precision the input has. Depending on the input data, this can
    cause the results to be inaccurate, especially for `float32` (see
    example below). Specifying a higher-precision accumulator using the
    `dtype` keyword can alleviate this issue.
    
    By default, `float16` results are computed using `float32` intermediates
    for extra precision.
    
    Examples
    --------
    >>> a = np.array([[1, 2], [3, 4]])
    >>> np.mean(a)
    2.5
    >>> np.mean(a, axis=0)
    array([2., 3.])
    >>> np.mean(a, axis=1)
    array([1.5, 3.5])
    
    In single precision, `mean` can be inaccurate:
    
    >>> a = np.zeros((2, 512*512), dtype=np.float32)
    >>> a[0, :] = 1.0
    >>> a[1, :] = 0.1
    >>> np.mean(a)
    0.54999924
    
    Computing the mean in float64 is more accurate:
    
    >>> np.mean(a, dtype=np.float64)
    0.55000000074505806 # may vary
    
    Specifying a where argument:
    
    >>> a = np.array([[5, 9, 13], [14, 10, 12], [11, 15, 19]])
    >>> np.mean(a)
    12.0
    >>> np.mean(a, where=[[True], [False], [False]])
    9.0
    """
    kwargs = {}
    if keepdims is not np._NoValue:
        kwargs['keepdims'] = keepdims
    if where is not np._NoValue:
        kwargs['where'] = where
    if type(a) is not mu.ndarray:
        try:
            mean = a.mean
        except AttributeError:
            pass
        else:
            return mean(axis=axis, dtype=dtype, out=out, **kwargs)
    
    return _methods._mean(a, axis=axis, dtype=dtype,
                          out=out, **kwargs)
# 定义一个私有函数 _std_dispatcher,用于分发参数,并返回元组 (a, where, out, mean)
def _std_dispatcher(a, axis=None, dtype=None, out=None, ddof=None,
                    keepdims=None, *, where=None, mean=None, correction=None):
    return (a, where, out, mean)


# 使用装饰器 array_function_dispatch,将 _std_dispatcher 注册为 std 函数的分发器
@array_function_dispatch(_std_dispatcher)
# 定义 std 函数,计算沿指定轴的标准差
def std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue, *,
        where=np._NoValue, mean=np._NoValue, correction=np._NoValue):
    r"""
    Compute the standard deviation along the specified axis.

    Returns the standard deviation, a measure of the spread of a distribution,
    of the array elements. The standard deviation is computed for the
    flattened array by default, otherwise over the specified axis.

    Parameters
    ----------
    a : array_like
        Calculate the standard deviation of these values.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the standard deviation is computed. The
        default is to compute the standard deviation of the flattened array.

        .. versionadded:: 1.7.0

        If this is a tuple of ints, a standard deviation is performed over
        multiple axes, instead of a single axis or all the axes as before.
    dtype : dtype, optional
        Type to use in computing the standard deviation. For arrays of
        integer type the default is float64, for arrays of float types it is
        the same as the array type.
    out : ndarray, optional
        Alternative output array in which to place the result. It must have
        the same shape as the expected output but the type (of the calculated
        values) will be cast if necessary.
        See :ref:`ufuncs-output-type` for more details.
    ddof : {int, float}, optional
        Means Delta Degrees of Freedom.  The divisor used in calculations
        is ``N - ddof``, where ``N`` represents the number of elements.
        By default `ddof` is zero. See Notes for details about use of `ddof`.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the input array.

        If the default value is passed, then `keepdims` will not be
        passed through to the `std` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.
    where : array_like of bool, optional
        Elements to include in the standard deviation.
        See `~numpy.ufunc.reduce` for details.

        .. versionadded:: 1.20.0

    mean : array_like, optional
        Provide the mean to prevent its recalculation. The mean should have
        a shape as if it was calculated with ``keepdims=True``.
        The axis for the calculation of the mean should be the same as used in
        the call to this std function.

        .. versionadded:: 1.26.0
    correction : {int, float}, optional
        # 参数 correction 可以是 int 或 float 类型,可选的 Array API 兼容名称,用于参数 ddof。
        # 同一时间只能提供其中之一。

        .. versionadded:: 2.0.0
        # 添加于版本 2.0.0

    Returns
    -------
    standard_deviation : ndarray, see dtype parameter above.
        # 返回标准差的 ndarray,参见上述的 dtype 参数。
        # 如果 `out` 为 None,返回包含标准差的新数组;否则返回对输出数组的引用。

    See Also
    --------
    var, mean, nanmean, nanstd, nanvar
    :ref:`ufuncs-output-type`
        # 参见也有 var, mean, nanmean, nanstd, nanvar 和 :ref:`ufuncs-output-type`

    Notes
    -----
    There are several common variants of the array standard deviation
    calculation. Assuming the input `a` is a one-dimensional NumPy array
    and ``mean`` is either provided as an argument or computed as
    ``a.mean()``, NumPy computes the standard deviation of an array as::

        N = len(a)
        d2 = abs(a - mean)**2  # abs is for complex `a`
        var = d2.sum() / (N - ddof)  # note use of `ddof`
        std = var**0.5
        # 计算数组标准差的常见变体之一。假设输入 `a` 是一维 NumPy 数组,
        # `mean` 作为参数提供或计算为 `a.mean()`,NumPy 计算数组的标准差为:

    Different values of the argument `ddof` are useful in different
    contexts. NumPy's default ``ddof=0`` corresponds with the expression:

    .. math::

        \sqrt{\frac{\sum_i{|a_i - \bar{a}|^2 }}{N}}

    which is sometimes called the "population standard deviation" in the field
    of statistics because it applies the definition of standard deviation to
    `a` as if `a` were a complete population of possible observations.
    # 参数 `ddof` 的不同值在不同的上下文中很有用。NumPy 的默认值 `ddof=0`
    # 对应于表达式:

    .. math::

        \sqrt{\frac{\sum_i{|a_i - \bar{a}|^2 }}{N}}
        # 这在统计学领域有时被称为 "总体标准差",因为它将标准差的定义应用于 `a`,
        # 就好像 `a` 是可能观察到的全部总体。

    Many other libraries define the standard deviation of an array
    differently, e.g.:

    .. math::

        \sqrt{\frac{\sum_i{|a_i - \bar{a}|^2 }}{N - 1}}
        # 许多其他库以不同的方式定义数组的标准差,例如:

    In statistics, the resulting quantity is sometimed called the "sample
    standard deviation" because if `a` is a random sample from a larger
    population, this calculation provides the square root of an unbiased
    estimate of the variance of the population. The use of :math:`N-1` in the
    denominator is often called "Bessel's correction" because it corrects for
    bias (toward lower values) in the variance estimate introduced when the
    sample mean of `a` is used in place of the true mean of the population.
    The resulting estimate of the standard deviation is still biased, but less
    than it would have been without the correction. For this quantity, use
    ``ddof=1``.
    # 在统计学中,由于 `a` 是来自更大总体的随机样本,该计算提供了总体方差的无偏估计的平方根,
    # 因此所得的数量有时被称为 "样本标准差"。在分母中使用 :math:`N-1` 通常被称为 "贝塞尔校正",
    # 因为它校正了当使用 `a` 的样本均值代替总体真实均值时引入的方差估计偏差(向更小值偏移)。
    # 所得的标准差估计仍然是有偏的,但比没有校正时要小。对于这个量,使用 `ddof=1`。

    Note that, for complex numbers, `std` takes the absolute
    value before squaring, so that the result is always real and nonnegative.
    # 注意,对于复数,`std` 在平方之前取绝对值,以便结果始终是实数且非负数。

    For floating-point input, the standard deviation is computed using the same
    precision the input has. Depending on the input data, this can cause
    the results to be inaccurate, especially for float32 (see example below).
    Specifying a higher-accuracy accumulator using the `dtype` keyword can
    alleviate this issue.
    # 对于浮点数输入,标准差使用与输入相同的精度计算。根据输入数据,这可能导致结果不准确,
    # 特别是对于 float32(参见下面的示例)。使用 `dtype` 关键字指定更高精度的累加器可以缓解此问题。

    Examples
    --------
    >>> a = np.array([[1, 2], [3, 4]])
    >>> np.std(a)
    1.1180339887498949 # may vary
    >>> np.std(a, axis=0)
    array([1.,  1.])
    >>> np.std(a, axis=1)
    array([0.5,  0.5])
    # 示例
    """
    Construct kwargs dictionary based on optional arguments for calculating standard deviation.
    
    :param a: Input array for which standard deviation is calculated.
    :param axis: Axis or axes along which the standard deviation is computed.
    :param dtype: Data type used in computing standard deviation.
    :param out: Output array.
    :param ddof: Delta degrees of freedom. The divisor used in calculations (default is 0).
    :param keepdims: If True, the axes which are reduced are left in the result as dimensions with size one.
    :param where: Array-like or boolean condition defining where the standard deviation should be computed.
    :param mean: Array of means to be used in standard deviation computation to save computation time.
    
    :return: Standard deviation of input array 'a' along specified axis/axes.
    """
    
    kwargs = {}
    
    # Check if keepdims is specified, add to kwargs if so
    if keepdims is not np._NoValue:
        kwargs['keepdims'] = keepdims
    
    # Check if where is specified, add to kwargs if so
    if where is not np._NoValue:
        kwargs['where'] = where
    
    # Check if mean is specified, add to kwargs if so
    if mean is not np._NoValue:
        kwargs['mean'] = mean
    
    # Handle correction and ddof arguments
    if correction != np._NoValue:
        # If correction is provided, ensure ddof is set accordingly
        if ddof != 0:
            raise ValueError("ddof and correction can't be provided simultaneously.")
        else:
            ddof = correction
    
    # Check if 'a' is not a numpy ndarray, try to retrieve std attribute
    if type(a) is not np.ndarray:
        try:
            std = a.std
        except AttributeError:
            pass
        else:
            # If 'std' attribute is found, call it with additional kwargs
            return std(axis=axis, dtype=dtype, out=out, ddof=ddof, **kwargs)
    
    # If 'a' is a numpy ndarray or 'std' attribute retrieval fails, use _methods._std function
    return _methods._std(a, axis=axis, dtype=dtype, out=out, ddof=ddof, **kwargs)
# 定义一个变量分派函数,用于返回参数元组 (a, where, out, mean)
def _var_dispatcher(a, axis=None, dtype=None, out=None, ddof=None,
                    keepdims=None, *, where=None, mean=None, correction=None):
    return (a, where, out, mean)

# 使用装饰器将 _var_dispatcher 函数注册为 var 函数的分派函数
@array_function_dispatch(_var_dispatcher)
# 定义计算方差的函数 var
def var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue, *,
        where=np._NoValue, mean=np._NoValue, correction=np._NoValue):
    r"""
    Compute the variance along the specified axis.

    Returns the variance of the array elements, a measure of the spread of a
    distribution.  The variance is computed for the flattened array by
    default, otherwise over the specified axis.

    Parameters
    ----------
    a : array_like
        Array containing numbers whose variance is desired.  If `a` is not an
        array, a conversion is attempted.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the variance is computed.  The default is to
        compute the variance of the flattened array.

        .. versionadded:: 1.7.0

        If this is a tuple of ints, a variance is performed over multiple axes,
        instead of a single axis or all the axes as before.
    dtype : data-type, optional
        Type to use in computing the variance.  For arrays of integer type
        the default is `float64`; for arrays of float types it is the same as
        the array type.
    out : ndarray, optional
        Alternate output array in which to place the result.  It must have
        the same shape as the expected output, but the type is cast if
        necessary.
    ddof : {int, float}, optional
        "Delta Degrees of Freedom": the divisor used in the calculation is
        ``N - ddof``, where ``N`` represents the number of elements. By
        default `ddof` is zero. See notes for details about use of `ddof`.
    keepdims : bool, optional
        If this is set to True, the axes which are reduced are left
        in the result as dimensions with size one. With this option,
        the result will broadcast correctly against the input array.

        If the default value is passed, then `keepdims` will not be
        passed through to the `var` method of sub-classes of
        `ndarray`, however any non-default value will be.  If the
        sub-class' method does not implement `keepdims` any
        exceptions will be raised.
    where : array_like of bool, optional
        Elements to include in the variance. See `~numpy.ufunc.reduce` for
        details.

        .. versionadded:: 1.20.0

    mean : array like, optional
        Provide the mean to prevent its recalculation. The mean should have
        a shape as if it was calculated with ``keepdims=True``.
        The axis for the calculation of the mean should be the same as used in
        the call to this var function.

        .. versionadded:: 1.26.0
    correction : {int, float}, optional
        # 参数 correction 可以是 int 或 float 类型,可选的,用于指定 ddof 参数的数组 API 兼容名称。同一时间只能提供其中之一。

        .. versionadded:: 2.0.0
        # 引入版本 2.0.0 添加了此参数。

    Returns
    -------
    variance : ndarray, see dtype parameter above
        # 返回值是一个 ndarray 数组,具体类型可以参考上面的 dtype 参数说明。
        如果 ``out=None``,返回一个包含方差的新数组;
        否则,返回对输出数组的引用。

    See Also
    --------
    std, mean, nanmean, nanstd, nanvar
    :ref:`ufuncs-output-type`
        # 参见其他函数:std、mean、nanmean、nanstd、nanvar,以及 ufuncs 输出类型的文档。

    Notes
    -----
    # 注意事项:

    There are several common variants of the array variance calculation.
    # 数组方差计算有几种常见的变体。

    Assuming the input `a` is a one-dimensional NumPy array and ``mean`` is
    either provided as an argument or computed as ``a.mean()``, NumPy
    computes the variance of an array as::
        # 假设输入 `a` 是一个一维的 NumPy 数组,并且 `mean` 要么作为参数提供,要么通过 `a.mean()` 计算,NumPy 计算数组的方差如下所示:

        N = len(a)
        # 计算数组 `a` 的长度为 N
        d2 = abs(a - mean)**2  # abs is for complex `a`
        # 计算绝对值平方后的差值,对于复数 `a` 使用 abs 函数
        var = d2.sum() / (N - ddof)  # note use of `ddof`
        # 计算方差,注意使用 `ddof`

    Different values of the argument `ddof` are useful in different
    contexts. NumPy's default ``ddof=0`` corresponds with the expression:
        # 参数 `ddof` 的不同值在不同的情况下有不同的用处。NumPy 默认的 `ddof=0` 对应以下表达式:

    .. math::

        \frac{\sum_i{|a_i - \bar{a}|^2 }}{N}
        # 这个表达式有时在统计学中称为 "总体方差",因为它将方差的定义应用于 `a`,就好像 `a` 是可能观察结果的完整总体。

    Many other libraries define the variance of an array differently, e.g.:
        # 许多其他库以不同的方式定义数组的方差,例如:

    .. math::

        \frac{\sum_i{|a_i - \bar{a}|^2}}{N - 1}
        # 在统计学中,这种结果有时称为 "样本方差",因为如果 `a` 是来自更大总体的随机样本,则此计算提供了总体方差的无偏估计。分母使用 `N-1` 是为了校正偏差,因为使用 `a` 的样本均值代替总体真实均值时引入了方差估计的偏向(朝向较低的值)。这种校正通常称为 "贝塞尔校正"。

    Note that for complex numbers, the absolute value is taken before
    squaring, so that the result is always real and nonnegative.
        # 注意,对于复数,取绝对值后再进行平方,以确保结果始终是实数且非负数。

    For floating-point input, the variance is computed using the same
    precision the input has.  Depending on the input data, this can cause
    the results to be inaccurate, especially for `float32` (see example
    below).  Specifying a higher-accuracy accumulator using the ``dtype``
    keyword can alleviate this issue.
        # 对于浮点数输入,方差的计算精度与输入数据一致。根据输入数据的不同,这可能会导致结果不准确,特别是对于 `float32`(参见下面的示例)。可以通过指定更高精度的累加器来缓解这个问题,使用 `dtype` 关键字。

    Examples
    --------
    # 示例:

    >>> a = np.array([[1, 2], [3, 4]])
    >>> np.var(a)
    1.25
        # 计算数组 `a` 的方差,结果为 1.25

    >>> np.var(a, axis=0)
    array([1.,  1.])
        # 沿着 axis=0 方向计算数组 `a` 的方差,结果为 [1., 1.]

    >>> np.var(a, axis=1)
    array([0.25,  0.25])
        # 沿着 axis=1 方向计算数组 `a` 的方差,结果为 [0.25, 0.25]

    In single precision, var() can be inaccurate:
        # 在单精度浮点数情况下,var() 可能不准确:

    >>> a = np.zeros((2, 512*512), dtype=np.float32)
    >>> a[0, :] = 1.0
    >>> a[1, :] = 0.1
    >>> np.var(a)
    0.20250003
        # 计算单精度下数组 `a` 的方差,结果为 0.20250003

    Computing the variance in float64 is more accurate:
        # 使用 float64 计算的方差更加精确:

    >>> np.var(a, dtype=np.float64)
    0.20249999932944759 # may vary
        # 使用 float64 数据类型计算数组 `a` 的方差,结果为 0.20249999932944759(可能有所变化)
    # 计算方差,使用公式 ((1-0.55)**2 + (0.1-0.55)**2)/2
    ((1-0.55)**2 + (0.1-0.55)**2)/2

    # 指定 where 参数的使用示例
    a = np.array([[14, 8, 11, 10], [7, 9, 10, 11], [10, 15, 5, 10]])
    # 计算数组 a 的方差
    np.var(a)
    # 输出结果可能会有所不同
    6.833333333333333 # may vary
    # 使用 where 参数限制计算的范围
    np.var(a, where=[[True], [True], [False]])
    # 返回结果 4.0

    # 使用 mean 关键字以节省计算时间
    import numpy as np
    from timeit import timeit

    a = np.array([[14, 8, 11, 10], [7, 9, 10, 11], [10, 15, 5, 10]])
    # 计算每行的平均值并保持维度
    mean = np.mean(a, axis=1, keepdims=True)

    g = globals()
    n = 10000
    # 使用 mean 关键字计算方差,并计算执行时间
    t1 = timeit("var = np.var(a, axis=1, mean=mean)", globals=g, number=n)
    # 普通计算方差的执行时间
    t2 = timeit("var = np.var(a, axis=1)", globals=g, number=n)
    # 打印节省的执行时间百分比
    print(f'Percentage execution time saved {100*(t2-t1)/t2:.0f}%')
    # doctest: +SKIP
    # 输出示例:Percentage execution time saved 32%

    """
    # 初始化一个空的关键字参数字典
    kwargs = {}
    # 如果 keepdims 不是 np._NoValue,则将其加入参数字典中
    if keepdims is not np._NoValue:
        kwargs['keepdims'] = keepdims
    # 如果 where 不是 np._NoValue,则将其加入参数字典中
    if where is not np._NoValue:
        kwargs['where'] = where
    # 如果 mean 不是 np._NoValue,则将其加入参数字典中
    if mean is not np._NoValue:
        kwargs['mean'] = mean

    # 如果 correction 不是 np._NoValue
    if correction != np._NoValue:
        # 如果 ddof 不为 0,则抛出 ValueError 异常
        if ddof != 0:
            raise ValueError(
                "ddof and correction can't be provided simultaneously."
            )
        else:
            # 否则将 correction 赋值给 ddof
            ddof = correction

    # 如果 a 的类型不是 mu.ndarray
    if type(a) is not mu.ndarray:
        try:
            # 尝试获取 a 的 var 属性
            var = a.var
        # 如果出现 AttributeError 异常则跳过
        except AttributeError:
            pass
        else:
            # 如果成功获取 var 属性,则调用其方法计算方差并返回结果
            return var(axis=axis, dtype=dtype, out=out, ddof=ddof, **kwargs)

    # 否则调用 _methods 模块中的 _var 方法计算方差并返回结果
    return _methods._var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
                         **kwargs)
    ```