NumPy-源码解析-九十-

168 阅读55分钟

NumPy 源码解析(九十)

.\numpy\numpy\_core\_add_newdocs_scalars.py

"""
This file is separate from ``_add_newdocs.py`` so that it can be mocked out by
our sphinx ``conf.py`` during doc builds, where we want to avoid showing
platform-dependent information.
"""

# 导入系统操作模块和操作系统模块
import sys
import os
# 导入numpy的数据类型模块
from numpy._core import dtype
# 导入numpy的数据类型别名模块
from numpy._core import numerictypes as _numerictypes
# 导入numpy的函数基础模块中的add_newdoc函数
from numpy._core.function_base import add_newdoc

##############################################################################
#
# Documentation for concrete scalar classes
#
##############################################################################

# 定义一个函数,用于生成类型别名的生成器
def numeric_type_aliases(aliases):
    def type_aliases_gen():
        # 遍历提供的别名列表
        for alias, doc in aliases:
            try:
                # 尝试获取_numerictypes模块中的别名对应的类型
                alias_type = getattr(_numerictypes, alias)
            except AttributeError:
                # 如果别名在_numerictypes模块中不存在,则跳过
                # 不同平台可能存在的别名集合不同
                pass
            else:
                # 如果获取成功,则生成一个元组(alias_type, alias, doc)
                yield (alias_type, alias, doc)
    # 返回类型别名生成器生成的列表
    return list(type_aliases_gen())

# 定义一个可能的类型别名列表
possible_aliases = numeric_type_aliases([
    ('int8', '8-bit signed integer (``-128`` to ``127``)'),
    ('int16', '16-bit signed integer (``-32_768`` to ``32_767``)'),
    ('int32', '32-bit signed integer (``-2_147_483_648`` to ``2_147_483_647``)'),
    ('int64', '64-bit signed integer (``-9_223_372_036_854_775_808`` to ``9_223_372_036_854_775_807``)'),
    ('intp', 'Signed integer large enough to fit pointer, compatible with C ``intptr_t``'),
    ('uint8', '8-bit unsigned integer (``0`` to ``255``)'),
    ('uint16', '16-bit unsigned integer (``0`` to ``65_535``)'),
    ('uint32', '32-bit unsigned integer (``0`` to ``4_294_967_295``)'),
    ('uint64', '64-bit unsigned integer (``0`` to ``18_446_744_073_709_551_615``)'),
    ('uintp', 'Unsigned integer large enough to fit pointer, compatible with C ``uintptr_t``'),
    ('float16', '16-bit-precision floating-point number type: sign bit, 5 bits exponent, 10 bits mantissa'),
    ('float32', '32-bit-precision floating-point number type: sign bit, 8 bits exponent, 23 bits mantissa'),
    ('float64', '64-bit precision floating-point number type: sign bit, 11 bits exponent, 52 bits mantissa'),
    ('float96', '96-bit extended-precision floating-point number type'),
    ('float128', '128-bit extended-precision floating-point number type'),
    ('complex64', 'Complex number type composed of 2 32-bit-precision floating-point numbers'),
    ('complex128', 'Complex number type composed of 2 64-bit-precision floating-point numbers'),
    ('complex192', 'Complex number type composed of 2 96-bit extended-precision floating-point numbers'),
    ('complex256', 'Complex number type composed of 2 128-bit extended-precision floating-point numbers'),
    ])

# 定义一个函数,尝试获取平台和机器信息
def _get_platform_and_machine():
    try:
        # 尝试获取当前操作系统的信息
        system, _, _, _, machine = os.uname()
    # 捕获 AttributeError 异常
    except AttributeError:
        # 获取当前操作系统平台信息
        system = sys.platform
        # 如果系统为 'win32',获取处理器架构信息
        if system == 'win32':
            machine = os.environ.get('PROCESSOR_ARCHITEW6432', '') \
                    or os.environ.get('PROCESSOR_ARCHITECTURE', '')
        else:
            # 对于非 'win32' 系统,设置处理器架构为 'unknown'
            machine = 'unknown'
    # 返回系统平台信息和处理器架构信息
    return system, machine
_system, _machine = _get_platform_and_machine()
_doc_alias_string = f":Alias on this platform ({_system} {_machine}):"

# 定义函数,用于为给定的标量类型添加新的文档
def add_newdoc_for_scalar_type(obj, fixed_aliases, doc):
    # 获取 _numerictypes 模块中名为 obj 的对象
    o = getattr(_numerictypes, obj)

    # 获取对象 o 的字符编码
    character_code = dtype(o).char

    # 如果 obj 不等于 o 的名称,则生成规范名称文档
    canonical_name_doc = "" if obj == o.__name__ else \
                        f":Canonical name: `numpy.{obj}`\n    "

    # 根据 fixed_aliases 生成别名文档
    if fixed_aliases:
        alias_doc = ''.join(f":Alias: `numpy.{alias}`\n    "
                            for alias in fixed_aliases)
    else:
        alias_doc = ''

    # 根据 possible_aliases 中的信息生成别名文档,并结合 _doc_alias_string
    alias_doc += ''.join(f"{_doc_alias_string} `numpy.{alias}`: {doc}.\n    "
                         for (alias_type, alias, doc) in possible_aliases if alias_type is o)

    # 构建完整的文档字符串,包括传入的 doc 参数以及其他详细信息
    docstring = f"""
    {doc.strip()}  # 去除首尾空白字符

    :Character code: ``'{character_code}'``
    {canonical_name_doc}{alias_doc}
    """

    # 调用 add_newdoc 函数,将文档添加到 'numpy._core.numerictypes' 模块的 obj 对象上
    add_newdoc('numpy._core.numerictypes', obj, docstring)

# 布尔类型的文档字符串
_bool_docstring = (
    """
    Boolean type (True or False), stored as a byte.

    .. warning::

       The :class:`bool` type is not a subclass of the :class:`int_` type
       (the :class:`bool` is not even a number type). This is different
       than Python's default implementation of :class:`bool` as a
       sub-class of :class:`int`.
    """
)

# 分别为 'bool', 'bool_', 'byte', 'short', 'intc' 等类型添加新的文档
add_newdoc_for_scalar_type('bool', [], _bool_docstring)
add_newdoc_for_scalar_type('bool_', [], _bool_docstring)
add_newdoc_for_scalar_type('byte', [],
    """
    Signed integer type, compatible with C ``char``.
    """)
add_newdoc_for_scalar_type('short', [],
    """
    Signed integer type, compatible with C ``short``.
    """)
add_newdoc_for_scalar_type('intc', [],
    """
    Signed integer type, compatible with C ``int``.
    """)

# TODO: These docs probably need an if to highlight the default rather than
#       the C-types (and be correct).

# 为 'int_' 类型添加新的文档,描述其作为默认有符号整数类型的特性
add_newdoc_for_scalar_type('int_', [],
    """
    Default signed integer type, 64bit on 64bit systems and 32bit on 32bit
    systems.
    """)

# 为 'longlong', 'ubyte', 'ushort', 'uintc' 等类型添加新的文档
add_newdoc_for_scalar_type('longlong', [],
    """
    Signed integer type, compatible with C ``long long``.
    """)
add_newdoc_for_scalar_type('ubyte', [],
    """
    Unsigned integer type, compatible with C ``unsigned char``.
    """)
add_newdoc_for_scalar_type('ushort', [],
    """
    Unsigned integer type, compatible with C ``unsigned short``.
    """)
add_newdoc_for_scalar_type('uintc', [],
    """
    Unsigned integer type, compatible with C ``unsigned int``.
    """)

# 为 'uint', 'ulonglong', 'half', 'single' 等类型添加新的文档
add_newdoc_for_scalar_type('uint', [],
    """
    Unsigned signed integer type, 64bit on 64bit systems and 32bit on 32bit
    systems.
    """)
add_newdoc_for_scalar_type('ulonglong', [],
    """
    Signed integer type, compatible with C ``unsigned long long``.
    """)
add_newdoc_for_scalar_type('half', [],
    """
    Half-precision floating-point number type.
    """)
add_newdoc_for_scalar_type('single', [],
    """
    Single-precision floating-point number type.
    """)
    # 定义一个新的类`Single-precision floating-point number type`,它兼容C语言中的`float`。
    Single-precision floating-point number type, compatible with C ``float``.
    """
# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('double', [],
    """
    双精度浮点数类型,与 Python 中的 :class:`float` 和 C 的 ``double`` 兼容。
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('longdouble', [],
    """
    扩展精度浮点数类型,与 C 的 ``long double`` 兼容,但不一定与 IEEE 754 四倍精度兼容。
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('csingle', [],
    """
    复数类型,由两个单精度浮点数组成。
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('cdouble', [],
    """
    复数类型,由两个双精度浮点数组成,与 Python 的 :class:`complex` 兼容。
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('clongdouble', [],
    """
    复数类型,由两个扩展精度浮点数组成。
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('object_', [],
    """
    任意 Python 对象。
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('str_', [],
    r"""
    Unicode 字符串。

    此类型会去除尾部的空字符。

    >>> s = np.str_("abc\x00")
    >>> s
    'abc'

    不同于内置的 :class:`str`,此类型支持
    :ref:`python:bufferobjects`,以 UCS4 的形式展示其内容:

    >>> m = memoryview(np.str_("abc"))
    >>> m.format
    '3w'
    >>> m.tobytes()
    b'a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00'
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('bytes_', [],
    r"""
    字节串。

    在数组中使用时,此类型会去除尾部的空字节。
    """)

# 为指定的标量类型添加新的文档字符串
add_newdoc_for_scalar_type('void', [],
    r"""
    np.void(length_or_data, /, dtype=None)

    创建一个新的结构化或非结构化的空标量。

    参数
    ----------
    length_or_data : int, array-like, bytes-like, object
       长度或字节数据,用于创建非结构化的空标量。当指定 dtype 时,可以是要存储在新标量中的数据。
       这可以是一个类似数组的对象,此时可能返回一个数组。
    dtype : dtype, optional
       如果提供,则为新标量的数据类型。该数据类型必须是 "void" 类型(即结构化或非结构化的空标量)。

       .. versionadded:: 1.24

    注意
    -----
    由于历史原因和空标量可以表示任意字节数据和结构化数据类型的特性,
    空构造函数有三种调用约定:

    1. ``np.void(5)`` 创建一个填充有五个 ``\0`` 字节的 ``dtype="V5"`` 标量。其中的 5 可以是 Python 或 NumPy 的整数。
    2. ``np.void(b"bytes-like")`` 从字节串创建一个空标量。数据类型的项大小将匹配字节串长度,这里是 ``"V10"``。
    3. 当传递 ``dtype=`` 时,调用与创建数组类似。但是返回的是空标量而不是数组。

    请参阅示例,展示了所有三种不同的约定。

    示例
    """)
    # 创建一个空的 NumPy void 对象,参数为整数 5,默认使用 8 字节填充
    np.void(5)
    
    # 创建一个 NumPy void 对象,参数为字节序列 b'abcd',使用对应的 ASCII 码填充
    np.void(b'\x00\x00\x00\x00\x00')
    
    # 创建一个 NumPy void 对象,参数为元组 (3.2, b'eggs'),指定数据类型为浮点数和字节串,分别对应字段 'f0' 和 'f1'
    np.void((3.2, b'eggs'), dtype=[('f0', '<f8'), ('f1', 'S5')])
    
    # 创建一个 NumPy void 对象,参数为整数 3,指定数据类型为带有字段 'x' 和 'y' 的字节串
    np.void((3, 3), dtype=[('x', 'i1'), ('y', 'i1')])
# 为 datetime64 类型添加新的文档字符串
add_newdoc_for_scalar_type('datetime64', [],
    """
    如果从 64 位整数创建,则表示相对于 ``1970-01-01T00:00:00`` 的偏移量。
    如果从字符串创建,则字符串可以是 ISO 8601 日期或日期时间格式。
    
    当解析包含时区的字符串以创建 datetime 对象时(以 'Z' 或时区偏移量结尾),将丢弃时区并给出用户警告。
    
    Datetime64 对象应被视为 UTC,因此偏移量为 +0000。

    >>> np.datetime64(10, 'Y')
    np.datetime64('1980')
    >>> np.datetime64('1980', 'Y')
    np.datetime64('1980')
    >>> np.datetime64(10, 'D')
    np.datetime64('1970-01-11')

    更多信息请参见 :ref:`arrays.datetime`。
    """)

# 为 timedelta64 类型添加新的文档字符串
add_newdoc_for_scalar_type('timedelta64', [],
    """
    作为 64 位整数存储的 timedelta。

    更多信息请参见 :ref:`arrays.datetime`。
    """)

# 为 integer 类型的 is_integer 方法添加新的文档字符串
add_newdoc('numpy._core.numerictypes', "integer", ('is_integer',
    """
    integer.is_integer() -> bool

    如果数是有限的整数值,则返回 ``True``。

    .. versionadded:: 1.22

    示例
    --------
    >>> np.int64(-2).is_integer()
    True
    >>> np.uint32(5).is_integer()
    True
    """))

# 为浮点类型(half, single, double, longdouble)的 as_integer_ratio 方法添加新的文档字符串
for float_name in ('half', 'single', 'double', 'longdouble'):
    add_newdoc('numpy._core.numerictypes', float_name, ('as_integer_ratio',
        """
        {ftype}.as_integer_ratio() -> (int, int)

        返回一对整数,其比率恰好等于原始浮点数,并且具有正的分母。
        对无穷大返回 `OverflowError`,对 NaN 返回 `ValueError`。

        >>> np.{ftype}(10.0).as_integer_ratio()
        (10, 1)
        >>> np.{ftype}(0.0).as_integer_ratio()
        (0, 1)
        >>> np.{ftype}(-.25).as_integer_ratio()
        (-1, 4)
        """.format(ftype=float_name)))

    # 为浮点类型(half, single, double, longdouble)的 is_integer 方法添加新的文档字符串
    add_newdoc('numpy._core.numerictypes', float_name, ('is_integer',
        f"""
        {float_name}.is_integer() -> bool

        如果浮点数是有限的整数值,则返回 ``True``;否则返回 ``False``。

        .. versionadded:: 1.22

        示例
        --------
        >>> np.{float_name}(-2.0).is_integer()
        True
        >>> np.{float_name}(3.2).is_integer()
        False
        """))

# 为整数类型(int8, uint8, int16, uint16, int32, uint32, int64, uint64)添加新的文档字符串
for int_name in ('int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32',
        'int64', 'uint64'):
    # 通过检查类型码,为有符号情况添加负数示例
    # 使用 add_newdoc 函数添加文档字符串到指定的 numpy._core.numerictypes 模块的 int_name 中
    add_newdoc('numpy._core.numerictypes', int_name, ('bit_count',
        # 定义 bit_count 方法的文档字符串,描述其作用和用法
        f"""
        {int_name}.bit_count() -> int

        Computes the number of 1-bits in the absolute value of the input.
        Analogous to the builtin `int.bit_count` or ``popcount`` in C++.

        Examples
        --------
        >>> np.{int_name}(127).bit_count()
        7""" +
        # 如果 int_name 对应的数据类型是小写,则添加额外的例子说明
        (f"""
        >>> np.{int_name}(-127).bit_count()
        7
        """ if dtype(int_name).char.islower() else "")))

.\numpy\numpy\_core\_asarray.py

"""
Functions in the ``as*array`` family that promote array-likes into arrays.

`require` fits this category despite its name not matching this pattern.
"""
# 从overrides模块导入必要的函数和类
from .overrides import (
    array_function_dispatch,
    set_array_function_like_doc,
    set_module,
)
# 从multiarray模块导入array和asanyarray函数
from .multiarray import array, asanyarray

# 定义模块公开的函数名列表
__all__ = ["require"]

# 定义可能的标志和其对应的规范化标志
POSSIBLE_FLAGS = {
    'C': 'C', 'C_CONTIGUOUS': 'C', 'CONTIGUOUS': 'C',
    'F': 'F', 'F_CONTIGUOUS': 'F', 'FORTRAN': 'F',
    'A': 'A', 'ALIGNED': 'A',
    'W': 'W', 'WRITEABLE': 'W',
    'O': 'O', 'OWNDATA': 'O',
    'E': 'E', 'ENSUREARRAY': 'E'
}

# 使用装饰器设定文档字符串的数组函数行为
@set_array_function_like_doc
# 设置模块名为'numpy'
@set_module('numpy')
def require(a, dtype=None, requirements=None, *, like=None):
    """
    Return an ndarray of the provided type that satisfies requirements.

    This function is useful to be sure that an array with the correct flags
    is returned for passing to compiled code (perhaps through ctypes).

    Parameters
    ----------
    a : array_like
       The object to be converted to a type-and-requirement-satisfying array.
    dtype : data-type
       The required data-type. If None preserve the current dtype. If your
       application requires the data to be in native byteorder, include
       a byteorder specification as a part of the dtype specification.
    requirements : str or sequence of str
       The requirements list can be any of the following

       * 'F_CONTIGUOUS' ('F') - ensure a Fortran-contiguous array
       * 'C_CONTIGUOUS' ('C') - ensure a C-contiguous array
       * 'ALIGNED' ('A')      - ensure a data-type aligned array
       * 'WRITEABLE' ('W')    - ensure a writable array
       * 'OWNDATA' ('O')      - ensure an array that owns its own data
       * 'ENSUREARRAY', ('E') - ensure a base array, instead of a subclass
    ${ARRAY_FUNCTION_LIKE}

        .. versionadded:: 1.20.0

    Returns
    -------
    out : ndarray
        Array with specified requirements and type if given.

    See Also
    --------
    asarray : Convert input to an ndarray.
    asanyarray : Convert to an ndarray, but pass through ndarray subclasses.
    ascontiguousarray : Convert input to a contiguous array.
    asfortranarray : Convert input to an ndarray with column-major
                     memory order.
    ndarray.flags : Information about the memory layout of the array.

    Notes
    -----
    The returned array will be guaranteed to have the listed requirements
    by making a copy if needed.

    Examples
    --------
    >>> x = np.arange(6).reshape(2,3)
    >>> x.flags
      C_CONTIGUOUS : True
      F_CONTIGUOUS : False
      OWNDATA : False
      WRITEABLE : True
      ALIGNED : True
      WRITEBACKIFCOPY : False

    >>> y = np.require(x, dtype=np.float32, requirements=['A', 'O', 'W', 'F'])
    >>> y.flags
      C_CONTIGUOUS : False
      F_CONTIGUOUS : True
      OWNDATA : True
      WRITEABLE : True
      ALIGNED : True
      WRITEBACKIFCOPY : False

    """
    # 如果参数 like 不为 None,则调用 _require_with_like 函数,并传入相关参数
    if like is not None:
        return _require_with_like(
            like,
            a,
            dtype=dtype,
            requirements=requirements,
        )
    
    # 如果 requirements 为空,则将 a 转换为任意数组,使用指定的数据类型 dtype
    if not requirements:
        return asanyarray(a, dtype=dtype)
    
    # 将 requirements 转换为大写,并从 POSSIBLE_FLAGS 字典中获取相应的标志集合
    requirements = {POSSIBLE_FLAGS[x.upper()] for x in requirements}
    
    # 如果集合中包含 'E',则移除 'E' 并设置 subok 为 False,否则设置为 True
    if 'E' in requirements:
        requirements.remove('E')
        subok = False
    else:
        subok = True
    
    # 默认设置数组的存储顺序为 'A'(任意顺序)
    order = 'A'
    
    # 如果 requirements 中包含 {'C', 'F'},则抛出 ValueError 异常,因为不能同时指定 "C" 和 "F" 顺序
    if requirements >= {'C', 'F'}:
        raise ValueError('Cannot specify both "C" and "F" order')
    elif 'F' in requirements:
        # 如果 requirements 中包含 'F',则设置数组的存储顺序为 'F',并移除 'F'
        order = 'F'
        requirements.remove('F')
    elif 'C' in requirements:
        # 如果 requirements 中包含 'C',则设置数组的存储顺序为 'C',并移除 'C'
        order = 'C'
        requirements.remove('C')
    
    # 使用指定的数据类型 dtype 和存储顺序 order,创建数组 arr,并根据 subok 参数决定是否允许子类化
    arr = array(a, dtype=dtype, order=order, copy=None, subok=subok)
    
    # 遍历 requirements 中的每个属性,如果 arr 不满足该属性的标志,则返回 arr 的副本,并设置存储顺序 order
    for prop in requirements:
        if not arr.flags[prop]:
            return arr.copy(order)
    
    # 如果所有 requirements 中的属性都被满足,则返回原始的 arr 数组
    return arr
# 使用array_function_dispatch()函数装饰require函数,并将结果赋值给_require_with_like变量
_require_with_like = array_function_dispatch()(require)

.\numpy\numpy\_core\_asarray.pyi

# 导入所需模块和类型定义
from collections.abc import Iterable
from typing import Any, TypeVar, overload, Literal

from numpy._typing import NDArray, DTypeLike, _SupportsArrayFunc

# 定义类型变量
_ArrayType = TypeVar("_ArrayType", bound=NDArray[Any])

# 定义需求标记的字面量类型
_Requirements = Literal[
    "C", "C_CONTIGUOUS", "CONTIGUOUS",
    "F", "F_CONTIGUOUS", "FORTRAN",
    "A", "ALIGNED",
    "W", "WRITEABLE",
    "O", "OWNDATA"
]
# 定义带有'E'需求标记的字面量类型
_E = Literal["E", "ENSUREARRAY"]
_RequirementsWithE = _Requirements | _E

# 函数重载,用于对输入数组或对象施加特定要求
@overload
def require(
    a: _ArrayType,
    dtype: None = ...,
    requirements: None | _Requirements | Iterable[_Requirements] = ...,
    *,
    like: _SupportsArrayFunc = ...
) -> _ArrayType: ...
@overload
def require(
    a: object,
    dtype: DTypeLike = ...,
    requirements: _E | Iterable[_RequirementsWithE] = ...,
    *,
    like: _SupportsArrayFunc = ...
) -> NDArray[Any]: ...
@overload
def require(
    a: object,
    dtype: DTypeLike = ...,
    requirements: None | _Requirements | Iterable[_Requirements] = ...,
    *,
    like: _SupportsArrayFunc = ...
) -> NDArray[Any]: ...

.\numpy\numpy\_core\_dtype.py

"""
A place for code to be called from the implementation of np.dtype

String handling is much easier to do correctly in python.
"""
# 导入 numpy 库,并使用别名 np
import numpy as np

# 将数据类型的种类映射为相应的基本类型名称
_kind_to_stem = {
    'u': 'uint',    # 无符号整数
    'i': 'int',     # 有符号整数
    'c': 'complex', # 复数
    'f': 'float',   # 浮点数
    'b': 'bool',    # 布尔值
    'V': 'void',    # void(空类型)
    'O': 'object',  # Python 对象
    'M': 'datetime',# 日期时间
    'm': 'timedelta', # 时间间隔
    'S': 'bytes',   # 字节串
    'U': 'str',     # Unicode 字符串
}

# 根据数据类型返回其种类对应的基本类型名称
def _kind_name(dtype):
    try:
        return _kind_to_stem[dtype.kind]
    except KeyError as e:
        raise RuntimeError(
            "internal dtype error, unknown kind {!r}"
            .format(dtype.kind)
        ) from None

# 根据数据类型返回其字符串表示形式
def __str__(dtype):
    if dtype.fields is not None:
        return _struct_str(dtype, include_align=True)  # 返回结构化数据类型的字符串表示
    elif dtype.subdtype:
        return _subarray_str(dtype)  # 返回子数组数据类型的字符串表示
    elif issubclass(dtype.type, np.flexible) or not dtype.isnative:
        return dtype.str  # 返回灵活数据类型或非本机字节顺序数据类型的字符串表示
    else:
        return dtype.name  # 返回数据类型的名称

# 返回数据类型的详细表示形式
def __repr__(dtype):
    arg_str = _construction_repr(dtype, include_align=False)  # 获取构造数据类型的字符串表示形式
    if dtype.isalignedstruct:
        arg_str = arg_str + ", align=True"  # 如果数据类型是对齐结构,则添加 align=True 参数
    return "dtype({})".format(arg_str)  # 返回数据类型的构造函数表示形式

# 解包数据类型字段的帮助函数,返回标准化后的字段信息
def _unpack_field(dtype, offset, title=None):
    """
    Helper function to normalize the items in dtype.fields.

    Call as:

    dtype, offset, title = _unpack_field(*dtype.fields[name])
    """
    return dtype, offset, title

# 检查数据类型是否为未定义大小的数据类型
def _isunsized(dtype):
    # PyDataType_ISUNSIZED
    return dtype.itemsize == 0  # 返回数据类型的元素大小是否为零

# 构造数据类型的字符串表示形式,不包括 'dtype()' 部分
def _construction_repr(dtype, include_align=False, short=False):
    """
    Creates a string repr of the dtype, excluding the 'dtype()' part
    surrounding the object. This object may be a string, a list, or
    a dict depending on the nature of the dtype. This
    is the object passed as the first parameter to the dtype
    constructor, and if no additional constructor parameters are
    given, will reproduce the exact memory layout.

    Parameters
    ----------
    short : bool
        If true, this creates a shorter repr using 'kind' and 'itemsize',
        instead of the longer type name.

    include_align : bool
        If true, this includes the 'align=True' parameter
        inside the struct dtype construction dict when needed. Use this flag
        if you want a proper repr string without the 'dtype()' part around it.

        If false, this does not preserve the
        'align=True' parameter or sticky NPY_ALIGNED_STRUCT flag for
        struct arrays like the regular repr does, because the 'align'
        flag is not part of first dtype constructor parameter. This
        mode is intended for a full 'repr', where the 'align=True' is
        provided as the second parameter.
    """
    if dtype.fields is not None:
        return _struct_str(dtype, include_align=include_align)  # 返回结构化数据类型的字符串表示
    elif dtype.subdtype:
        return _subarray_str(dtype)  # 返回子数组数据类型的字符串表示
    else:
        return _scalar_str(dtype, short=short)  # 返回标量数据类型的字符串表示

# 构造标量数据类型的字符串表示形式
def _scalar_str(dtype, short):
    byteorder = _byte_order_str(dtype)
    # 如果数据类型是布尔型(np.bool)
    if dtype.type == np.bool:
        # 如果需要简短表示(short为True),返回问号字符'?'作为表示
        if short:
            return "'?'"
        else:
            # 否则返回完整表示'bool'
            return "'bool'"

    # 如果数据类型是对象(np.object_)
    elif dtype.type == np.object_:
        # 对象引用在不同平台可能有不同大小,所以此处不应包含itemsize大小信息
        return "'O'"

    # 如果数据类型是字节串(np.bytes_)
    elif dtype.type == np.bytes_:
        # 如果是无大小限制的字节串,返回'S'
        if _isunsized(dtype):
            return "'S'"
        else:
            # 否则返回'S%d',其中%d是字节串的itemsize大小
            return "'S%d'" % dtype.itemsize

    # 如果数据类型是字符串(np.str_)
    elif dtype.type == np.str_:
        # 如果是无大小限制的字符串,返回'字节序U'格式的字符串
        if _isunsized(dtype):
            return "'%sU'" % byteorder
        else:
            # 否则返回'字节序U%d',其中%d是字符串的itemsize大小除以4的结果
            return "'%sU%d'" % (byteorder, dtype.itemsize / 4)

    # 如果数据类型是普通字符串(str)
    elif dtype.type == str:
        return "'T'"

    # 如果数据类型不是传统的数据类型
    elif not type(dtype)._legacy:
        # 返回形如'字节序类名大小位'的字符串表示
        return f"'{byteorder}{type(dtype).__name__}{dtype.itemsize * 8}'"

    # 对于void的子类,保持原样,但是历史上的repr实际上并不显示子类
    elif issubclass(dtype.type, np.void):
        # 如果是无大小限制的void类型,返回'V'
        if _isunsized(dtype):
            return "'V'"
        else:
            # 否则返回'V%d',其中%d是void类型的itemsize大小
            return "'V%d'" % dtype.itemsize

    # 如果数据类型是日期时间类型(np.datetime64)
    elif dtype.type == np.datetime64:
        # 返回形如'字节序M8元数据'的日期时间字符串表示
        return "'%sM8%s'" % (byteorder, _datetime_metadata_str(dtype))

    # 如果数据类型是时间间隔类型(np.timedelta64)
    elif dtype.type == np.timedelta64:
        # 返回形如'字节序m8元数据'的时间间隔字符串表示
        return "'%sm8%s'" % (byteorder, _datetime_metadata_str(dtype))

    # 如果数据类型是数值类型的子类型(np.number)
    elif np.issubdtype(dtype, np.number):
        # 如果需要简短表示(short为True),返回形如'字节序类型大小'的简短字符串表示
        if short or dtype.byteorder not in ('=', '|'):
            return "'%s%c%d'" % (byteorder, dtype.kind, dtype.itemsize)
        else:
            # 否则返回形如'类型名大小'的长字符串表示
            return "'%s%d'" % (_kind_name(dtype), 8*dtype.itemsize)

    # 如果数据类型是内置类型的标志(dtype.isbuiltin == 2)
    elif dtype.isbuiltin == 2:
        # 返回该内置类型的名称
        return dtype.type.__name__

    # 如果以上条件都不满足,抛出运行时错误
    else:
        raise RuntimeError(
            "Internal error: NumPy dtype unrecognized type number")
# 将数据类型的字节顺序规范化为 '<' 或 '>'
def _byte_order_str(dtype):
    # 创建一个新的数据类型对象,其字节顺序被交换
    swapped = np.dtype(int).newbyteorder('S')
    # 获取原生数据类型对象
    native = swapped.newbyteorder('S')

    # 获取当前数据类型的字节顺序
    byteorder = dtype.byteorder
    # 如果字节顺序为 '=',返回原生数据类型的字节顺序
    if byteorder == '=':
        return native.byteorder
    # 如果字节顺序为 'S',这条路径永远不会被执行
    if byteorder == 'S':
        # TODO: this path can never be reached
        return swapped.byteorder
    # 如果字节顺序为 '|',返回空字符串
    elif byteorder == '|':
        return ''
    else:
        # 否则返回当前字节顺序
        return byteorder


def _datetime_metadata_str(dtype):
    # TODO: this duplicates the C metastr_to_unicode functionality
    # 获取日期时间数据类型的单位和计数
    unit, count = np.datetime_data(dtype)
    # 如果单位为 'generic',返回空字符串
    if unit == 'generic':
        return ''
    # 如果计数为 1,返回格式化后的单位字符串,例如 '[unit]'
    elif count == 1:
        return '[{}]'.format(unit)
    # 否则返回格式化后的计数和单位字符串,例如 '[countunit]'
    else:
        return '[{}{}]'.format(count, unit)


def _struct_dict_str(dtype, includealignedflag):
    # 将字段名解包到列表 ls 中
    names = dtype.names
    fld_dtypes = []
    offsets = []
    titles = []
    # 遍历字段名列表
    for name in names:
        # 解包字段信息
        fld_dtype, offset, title = _unpack_field(*dtype.fields[name])
        fld_dtypes.append(fld_dtype)
        offsets.append(offset)
        titles.append(title)

    # 构建字典字符串

    # 根据打印模式确定冒号和字段分隔符
    if np._core.arrayprint._get_legacy_print_mode() <= 121:
        colon = ":"
        fieldsep = ","
    else:
        colon = ": "
        fieldsep = ", "

    # 首先添加字段名
    ret = "{'names'%s[" % colon
    ret += fieldsep.join(repr(name) for name in names)

    # 其次添加格式
    ret += "], 'formats'%s[" % colon
    ret += fieldsep.join(
        _construction_repr(fld_dtype, short=True) for fld_dtype in fld_dtypes)

    # 然后添加偏移量
    ret += "], 'offsets'%s[" % colon
    ret += fieldsep.join("%d" % offset for offset in offsets)

    # 如果存在标题,则添加标题信息
    if any(title is not None for title in titles):
        ret += "], 'titles'%s[" % colon
        ret += fieldsep.join(repr(title) for title in titles)

    # 最后添加项目大小信息
    ret += "], 'itemsize'%s%d" % (colon, dtype.itemsize)

    # 如果包含对齐标志并且数据类型是对齐的结构体,则添加对齐标志
    if (includealignedflag and dtype.isalignedstruct):
        ret += ", 'aligned'%sTrue}" % colon
    else:
        ret += "}"

    return ret


def _aligned_offset(offset, alignment):
    # 将偏移量向上舍入到最接近的对齐边界
    return - (-offset // alignment) * alignment


def _is_packed(dtype):
    """
    检查结构化数据类型 'dtype' 是否具有简单的布局,即所有字段按顺序排列,
    且没有额外的对齐填充。
    
    当返回 True 时,可以从字段名和数据类型的列表重建数据类型,而不需要额外的参数。

    复制了 C 中的 `is_dtype_struct_simple_unaligned_layout` 函数。
    """
    # 获取结构体的对齐属性
    align = dtype.isalignedstruct
    max_alignment = 1
    total_offset = 0
    # 遍历结构体类型(dtype)的每个字段名
    for name in dtype.names:
        # 解包字段信息,获取字段类型、偏移量和标题
        fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name])

        # 如果需要按照字段对齐要求调整偏移量
        if align:
            total_offset = _aligned_offset(total_offset, fld_dtype.alignment)
            # 更新最大对齐值
            max_alignment = max(max_alignment, fld_dtype.alignment)

        # 检查字段的偏移量是否与累计偏移量相等
        if fld_offset != total_offset:
            return False
        
        # 更新累计偏移量以包括当前字段的大小
        total_offset += fld_dtype.itemsize

    # 如果需要按照字段对齐要求调整最终的总偏移量
    if align:
        total_offset = _aligned_offset(total_offset, max_alignment)

    # 检查最终累计偏移量是否与结构体类型的总大小相等
    if total_offset != dtype.itemsize:
        return False
    
    # 结构体布局验证通过,返回True
    return True
def _struct_list_str(dtype):
    items = []
    # 遍历结构化数据类型中的字段名
    for name in dtype.names:
        # 解包字段元组
        fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name])

        item = "("
        # 如果存在标题,则格式化为特定字符串
        if title is not None:
            item += "({!r}, {!r}), ".format(title, name)
        else:
            item += "{!r}, ".format(name)
        # 处理特殊情况下的子数组
        if fld_dtype.subdtype is not None:
            base, shape = fld_dtype.subdtype
            item += "{}, {}".format(
                _construction_repr(base, short=True),
                shape
            )
        else:
            item += _construction_repr(fld_dtype, short=True)

        item += ")"
        # 将格式化后的字段信息添加到列表中
        items.append(item)

    # 返回包含所有字段信息的字符串列表
    return "[" + ", ".join(items) + "]"


def _struct_str(dtype, include_align):
    # 如果不需要包含对齐信息并且结构体是紧凑的,使用列表形式的字符串表示
    if not (include_align and dtype.isalignedstruct) and _is_packed(dtype):
        sub = _struct_list_str(dtype)
    else:
        # 否则使用字典形式的字符串表示
        sub = _struct_dict_str(dtype, include_align)

    # 如果数据类型不是默认的 void 类型,则返回带有模块名和数据类型的字符串表示
    if dtype.type != np.void:
        return "({t.__module__}.{t.__name__}, {f})".format(t=dtype.type, f=sub)
    else:
        # 否则返回结构体的字符串表示
        return sub


def _subarray_str(dtype):
    # 获取子数组的字符串表示,包括基础类型和形状信息
    base, shape = dtype.subdtype
    return "({}, {})".format(
        _construction_repr(base, short=True),
        shape
    )


def _name_includes_bit_suffix(dtype):
    if dtype.type == np.object_:
        # 对象类型不包含位后缀
        return False
    elif dtype.type == np.bool:
        # 布尔类型不包含位后缀
        return False
    elif dtype.type is None:
        # 未知类型包含位后缀
        return True
    elif np.issubdtype(dtype, np.flexible) and _isunsized(dtype):
        # 未指定类型不包含位后缀
        return False
    else:
        # 其他类型包含位后缀
        return True


def _name_get(dtype):
    # 返回数据类型的名称,考虑到是否包含位后缀和日期时间元数据
    if dtype.isbuiltin == 2:
        # 用户自定义数据类型返回其类型名称
        return dtype.type.__name__

    if not type(dtype)._legacy:
        name = type(dtype).__name__

    elif issubclass(dtype.type, np.void):
        # void 类型保留其名称,如 `record64`
        name = dtype.type.__name__
    else:
        name = _kind_name(dtype)

    # 如果需要,添加位数信息
    if _name_includes_bit_suffix(dtype):
        name += "{}".format(dtype.itemsize * 8)

    # 如果是日期时间类型,添加日期时间元数据
    if dtype.type in (np.datetime64, np.timedelta64):
        name += _datetime_metadata_str(dtype)

    return name

.\numpy\numpy\_core\_dtype_ctypes.py

"""
Conversion from ctypes to dtype.

In an ideal world, we could achieve this through the PEP3118 buffer protocol,
something like::

    def dtype_from_ctypes_type(t):
        # needed to ensure that the shape of `t` is within memoryview.format
        class DummyStruct(ctypes.Structure):
            _fields_ = [('a', t)]

        # empty to avoid memory allocation
        ctype_0 = (DummyStruct * 0)()
        mv = memoryview(ctype_0)

        # convert the struct, and slice back out the field
        return _dtype_from_pep3118(mv.format)['a']

Unfortunately, this fails because:

* ctypes cannot handle length-0 arrays with PEP3118 (bpo-32782)
* PEP3118 cannot represent unions, but both numpy and ctypes can
* ctypes cannot handle big-endian structs with PEP3118 (bpo-32780)
"""

# We delay-import ctypes for distributions that do not include it.
# While this module is not used unless the user passes in ctypes
# members, it is eagerly imported from numpy/_core/__init__.py.
import numpy as np


def _from_ctypes_array(t):
    """
    Convert a ctypes array to a numpy dtype.

    Args:
        t: ctypes array type

    Returns:
        numpy dtype corresponding to the ctypes array type
    """
    return np.dtype((dtype_from_ctypes_type(t._type_), (t._length_,)))


def _from_ctypes_structure(t):
    """
    Convert a ctypes structure to a numpy dtype.

    Args:
        t: ctypes structure type

    Raises:
        TypeError: If ctypes bitfields are encountered

    Returns:
        numpy dtype corresponding to the ctypes structure type
    """
    for item in t._fields_:
        if len(item) > 2:
            raise TypeError(
                "ctypes bitfields have no dtype equivalent")

    if hasattr(t, "_pack_"):
        import ctypes
        formats = []
        offsets = []
        names = []
        current_offset = 0
        for fname, ftyp in t._fields_:
            names.append(fname)
            formats.append(dtype_from_ctypes_type(ftyp))
            # Each type has a default offset, this is platform dependent
            # for some types.
            effective_pack = min(t._pack_, ctypes.alignment(ftyp))
            current_offset = (
                (current_offset + effective_pack - 1) // effective_pack
            ) * effective_pack
            offsets.append(current_offset)
            current_offset += ctypes.sizeof(ftyp)

        return np.dtype(dict(
            formats=formats,
            offsets=offsets,
            names=names,
            itemsize=ctypes.sizeof(t)))
    else:
        fields = []
        for fname, ftyp in t._fields_:
            fields.append((fname, dtype_from_ctypes_type(ftyp)))

        # by default, ctypes structs are aligned
        return np.dtype(fields, align=True)


def _from_ctypes_scalar(t):
    """
    Convert a ctypes scalar type to a numpy dtype.

    Args:
        t: ctypes scalar type

    Returns:
        numpy dtype corresponding to the ctypes scalar type
    """
    if getattr(t, '__ctype_be__', None) is t:
        return np.dtype('>' + t._type_)
    elif getattr(t, '__ctype_le__', None) is t:
        return np.dtype('<' + t._type_)
    else:
        return np.dtype(t._type_)


def _from_ctypes_union(t):
    """
    Convert a ctypes union to a numpy dtype.

    Args:
        t: ctypes union type
    """
    import ctypes
    formats = []
    offsets = []
    names = []
    for fname, ftyp in t._fields_:
        names.append(fname)
        formats.append(dtype_from_ctypes_type(ftyp))
        offsets.append(0)  # Union fields are offset to 0
    # 返回一个 NumPy 数据类型对象,该对象基于传入的参数构建
    return np.dtype(dict(
        formats=formats,    # 设置数据类型的格式列表
        offsets=offsets,    # 设置数据类型的偏移量列表
        names=names,        # 设置数据类型的字段名列表
        itemsize=ctypes.sizeof(t)))  # 设置数据类型的字节大小为给定类型 t 的大小
# 根据给定的 ctypes 类型 t 构造一个 dtype 对象
def dtype_from_ctypes_type(t):
    # 导入 _ctypes 模块,用于处理 ctypes 相关操作
    import _ctypes
    # 如果 t 是 _ctypes.Array 的子类,则调用 _from_ctypes_array 函数处理
    if issubclass(t, _ctypes.Array):
        return _from_ctypes_array(t)
    # 如果 t 是 _ctypes._Pointer 的子类,则抛出 TypeError
    elif issubclass(t, _ctypes._Pointer):
        raise TypeError("ctypes pointers have no dtype equivalent")
    # 如果 t 是 _ctypes.Structure 的子类,则调用 _from_ctypes_structure 函数处理
    elif issubclass(t, _ctypes.Structure):
        return _from_ctypes_structure(t)
    # 如果 t 是 _ctypes.Union 的子类,则调用 _from_ctypes_union 函数处理
    elif issubclass(t, _ctypes.Union):
        return _from_ctypes_union(t)
    # 如果 t 的 _type_ 属性是字符串,则调用 _from_ctypes_scalar 函数处理
    elif isinstance(getattr(t, '_type_', None), str):
        return _from_ctypes_scalar(t)
    # 如果 t 不属于以上任何一种类型,则抛出 NotImplementedError
    else:
        raise NotImplementedError(
            "Unknown ctypes type {}".format(t.__name__))

.\numpy\numpy\_core\_exceptions.py

"""
Various richly-typed exceptions, that also help us deal with string formatting
in python where it's easier.

By putting the formatting in `__str__`, we also avoid paying the cost for
users who silence the exceptions.
"""
from .._utils import set_module  # 导入相对路径中的 set_module 函数


def _unpack_tuple(tup):
    if len(tup) == 1:
        return tup[0]
    else:
        return tup


def _display_as_base(cls):
    """
    A decorator that makes an exception class look like its base.

    We use this to hide subclasses that are implementation details - the user
    should catch the base type, which is what the traceback will show them.

    Classes decorated with this decorator are subject to removal without a
    deprecation warning.
    """
    assert issubclass(cls, Exception)
    cls.__name__ = cls.__base__.__name__  # 将异常类的名称设为其基类的名称
    return cls


class UFuncTypeError(TypeError):
    """ Base class for all ufunc exceptions """
    def __init__(self, ufunc):
        self.ufunc = ufunc  # 初始化 ufunc 属性


@_display_as_base
class _UFuncNoLoopError(UFuncTypeError):
    """ Thrown when a ufunc loop cannot be found """
    def __init__(self, ufunc, dtypes):
        super().__init__(ufunc)
        self.dtypes = tuple(dtypes)  # 初始化 dtypes 属性为类型元组

    def __str__(self):
        return (
            "ufunc {!r} did not contain a loop with signature matching types "
            "{!r} -> {!r}"
        ).format(
            self.ufunc.__name__,
            _unpack_tuple(self.dtypes[:self.ufunc.nin]),  # 格式化字符串,显示 ufunc 名称和输入类型
            _unpack_tuple(self.dtypes[self.ufunc.nin:])  # 显示输出类型
        )


@_display_as_base
class _UFuncBinaryResolutionError(_UFuncNoLoopError):
    """ Thrown when a binary resolution fails """
    def __init__(self, ufunc, dtypes):
        super().__init__(ufunc, dtypes)  # 调用父类初始化方法
        assert len(self.dtypes) == 2  # 断言 dtypes 长度为 2

    def __str__(self):
        return (
            "ufunc {!r} cannot use operands with types {!r} and {!r}"
        ).format(
            self.ufunc.__name__, *self.dtypes  # 格式化字符串,显示 ufunc 名称和操作数类型
        )


@_display_as_base
class _UFuncCastingError(UFuncTypeError):
    def __init__(self, ufunc, casting, from_, to):
        super().__init__(ufunc)  # 调用父类初始化方法
        self.casting = casting  # 初始化 casting 属性
        self.from_ = from_  # 初始化 from_ 属性
        self.to = to  # 初始化 to 属性


@_display_as_base
class _UFuncInputCastingError(_UFuncCastingError):
    """ Thrown when a ufunc input cannot be casted """
    def __init__(self, ufunc, casting, from_, to, i):
        super().__init__(ufunc, casting, from_, to)  # 调用父类初始化方法
        self.in_i = i  # 初始化 in_i 属性

    def __str__(self):
        # only show the number if more than one input exists
        i_str = "{} ".format(self.in_i) if self.ufunc.nin != 1 else ""  # 根据输入数量确定显示的输入编号字符串
        return (
            "Cannot cast ufunc {!r} input {}from {!r} to {!r} with casting "
            "rule {!r}"
        ).format(
            self.ufunc.__name__, i_str, self.from_, self.to, self.casting  # 格式化字符串,显示 ufunc 名称、输入编号、源类型、目标类型和转换规则
        )


@_display_as_base
class _UFuncOutputCastingError(_UFuncCastingError):
    """ Thrown when a ufunc output cannot be casted """
    # 初始化方法,继承父类的构造方法,并添加了一个额外的实例变量 self.out_i
    def __init__(self, ufunc, casting, from_, to, i):
        super().__init__(ufunc, casting, from_, to)
        self.out_i = i

    # 返回描述对象的字符串表示,根据输出个数决定是否显示输出索引号
    def __str__(self):
        # 如果输出的个数不是1,则在字符串中包含输出索引号
        i_str = "{} ".format(self.out_i) if self.ufunc.nout != 1 else ""
        return (
            "Cannot cast ufunc {!r} output {}from {!r} to {!r} with casting "
            "rule {!r}"
        ).format(
            self.ufunc.__name__, i_str, self.from_, self.to, self.casting
        )
# 将 _ArrayMemoryError 类声明为一个装饰器的展示基类
@_display_as_base
# _ArrayMemoryError 类继承自内置的 MemoryError 类,用于表示无法分配数组时抛出的异常
class _ArrayMemoryError(MemoryError):
    
    """ Thrown when an array cannot be allocated"""
    # _ArrayMemoryError 类的初始化方法,接收 shape 和 dtype 两个参数
    def __init__(self, shape, dtype):
        self.shape = shape  # 将 shape 参数赋值给实例变量 self.shape
        self.dtype = dtype  # 将 dtype 参数赋值给实例变量 self.dtype

    # 定义 _total_size 属性方法,计算数组总大小的字节数
    @property
    def _total_size(self):
        num_bytes = self.dtype.itemsize  # 获取单个数组元素的字节数
        for dim in self.shape:
            num_bytes *= dim  # 根据数组各维度大小计算总字节数
        return num_bytes  # 返回计算得到的总字节数

    # 定义静态方法 _size_to_string,将字节数转换成合适的二进制大小字符串
    @staticmethod
    def _size_to_string(num_bytes):
        """ Convert a number of bytes into a binary size string """

        # https://en.wikipedia.org/wiki/Binary_prefix
        LOG2_STEP = 10
        STEP = 1024
        units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']

        # 计算应该使用的单位索引
        unit_i = max(num_bytes.bit_length() - 1, 1) // LOG2_STEP
        unit_val = 1 << (unit_i * LOG2_STEP)
        n_units = num_bytes / unit_val
        del unit_val

        # 确保选择的单位在四舍五入后是正确的
        if round(n_units) == STEP:
            unit_i += 1
            n_units /= STEP

        # 处理超出已定义单位范围的大小
        if unit_i >= len(units):
            new_unit_i = len(units) - 1
            n_units *= 1 << ((unit_i - new_unit_i) * LOG2_STEP)
            unit_i = new_unit_i

        unit_name = units[unit_i]  # 获取相应的单位名称
        # 格式化字符串,以合适的数字格式显示大小
        if unit_i == 0:
            # bytes 单位不显示小数点
            return '{:.0f} {}'.format(n_units, unit_name)
        elif round(n_units) < 1000:
            # 如果小于 1000,则显示三个有效数字
            return '{:#.3g} {}'.format(n_units, unit_name)
        else:
            # 否则显示所有数字
            return '{:#.0f} {}'.format(n_units, unit_name)

    # 定义 __str__ 方法,返回描述性字符串,说明无法分配数组内存的原因
    def __str__(self):
        size_str = self._size_to_string(self._total_size)  # 获取总大小的字符串表示
        return (
            "Unable to allocate {} for an array with shape {} and data type {}"
            .format(size_str, self.shape, self.dtype)
        )

.\numpy\numpy\_core\_internal.py

"""
A place for internal code

Some things are more easily handled Python.

"""
# 导入必要的模块和异常
import ast                 # AST(抽象语法树)模块,用于处理 Python 的语法分析树
import re                  # 正则表达式模块,用于字符串匹配和操作
import sys                 # sys 模块,提供对解释器相关的操作
import warnings            # 警告模块,用于发出警告信息

# 从 numpy 中导入特定模块和类
from ..exceptions import DTypePromotionError   # 导入自定义的数据类型提升异常类
from .multiarray import dtype, array, ndarray, promote_types, StringDType  # 导入多维数组相关类和函数
from numpy import _NoValue   # 导入 numpy 中的特定值

try:
    import ctypes   # 尝试导入 ctypes 模块,用于处理 C 语言数据类型
except ImportError:
    ctypes = None

# 判断当前 Python 解释器是否为 PyPy
IS_PYPY = sys.implementation.name == 'pypy'

# 根据系统的字节顺序设置数据格式化字符串
if sys.byteorder == 'little':
    _nbo = '<'
else:
    _nbo = '>'

# 定义一个函数用于处理字段列表,根据给定的对齐方式生成相应的字段信息
def _makenames_list(adict, align):
    allfields = []

    for fname, obj in adict.items():
        n = len(obj)
        if not isinstance(obj, tuple) or n not in (2, 3):
            raise ValueError("entry not a 2- or 3- tuple")
        if n > 2 and obj[2] == fname:
            continue
        num = int(obj[1])
        if num < 0:
            raise ValueError("invalid offset.")
        format = dtype(obj[0], align=align)
        if n > 2:
            title = obj[2]
        else:
            title = None
        allfields.append((fname, format, num, title))
    # 按偏移量排序
    allfields.sort(key=lambda x: x[2])
    names = [x[0] for x in allfields]
    formats = [x[1] for x in allfields]
    offsets = [x[2] for x in allfields]
    titles = [x[3] for x in allfields]

    return names, formats, offsets, titles

# 当一个字典在数据类型描述符中被使用时,在 PyArray_DescrConverter 函数中调用
# 如果字典缺少 "names" 和 "formats" 字段,则使用此函数生成数据类型
def _usefields(adict, align):
    try:
        names = adict[-1]
    except KeyError:
        names = None
    if names is None:
        names, formats, offsets, titles = _makenames_list(adict, align)
    else:
        formats = []
        offsets = []
        titles = []
        for name in names:
            res = adict[name]
            formats.append(res[0])
            offsets.append(res[1])
            if len(res) > 2:
                titles.append(res[2])
            else:
                titles.append(None)

    return dtype({"names": names,
                  "formats": formats,
                  "offsets": offsets,
                  "titles": titles}, align)


# 构建一个数组协议描述符列表
# 从描述符的字段属性中递归调用自身,直到最终找到没有字段的描述符,然后返回一个简单的类型字符串
def _array_descr(descriptor):
    fields = descriptor.fields
    if fields is None:
        subdtype = descriptor.subdtype
        if subdtype is None:
            if descriptor.metadata is None:
                return descriptor.str
            else:
                new = descriptor.metadata.copy()
                if new:
                    return (descriptor.str, new)
                else:
                    return descriptor.str
        else:
            return (_array_descr(subdtype[0]), subdtype[1])

    names = descriptor.names
    ordered_fields = [fields[x] + (x,) for x in names]
    result = []
    offset = 0
    # 对于给定的有序字段列表,依次处理每个字段
    for field in ordered_fields:
        # 检查字段的偏移量是否大于当前偏移量
        if field[1] > offset:
            # 计算当前字段的偏移量增量
            num = field[1] - offset
            # 将空字符串和偏移量增量信息追加到结果列表中
            result.append(('', f'|V{num}'))
            # 更新当前偏移量
            offset += num
        # 如果字段的偏移量小于当前偏移量,抛出数值错误异常
        elif field[1] < offset:
            raise ValueError(
                "dtype.descr is not defined for types with overlapping or "
                "out-of-order fields")
        
        # 如果字段列表的长度大于3,将字段名称设为元组(field[2], field[3])
        if len(field) > 3:
            name = (field[2], field[3])
        else:
            # 否则,将字段名称设为field[2]
            name = field[2]
        
        # 如果字段的子数据类型存在
        if field[0].subdtype:
            # 创建一个元组,包含字段名称、数组描述和子数据类型的信息
            tup = (name, _array_descr(field[0].subdtype[0]),
                   field[0].subdtype[1])
        else:
            # 否则,创建一个元组,包含字段名称和数组描述的信息
            tup = (name, _array_descr(field[0]))
        
        # 更新当前偏移量,加上当前字段的数据项大小
        offset += field[0].itemsize
        # 将处理后的字段信息元组追加到结果列表中
        result.append(tup)
    
    # 如果描述符的数据项大小大于当前偏移量
    if descriptor.itemsize > offset:
        # 计算描述符的数据项大小与当前偏移量之间的差值
        num = descriptor.itemsize - offset
        # 将空字符串和差值信息追加到结果列表中
        result.append(('', f'|V{num}'))
    
    # 返回最终的结果列表
    return result
# 正则表达式,用于解析格式字符串中的各个部分
format_re = re.compile(r'(?P<order1>[<>|=]?)'  # 匹配第一个字节顺序标识符(可选)
                       r'(?P<repeats> *[(]?[ ,0-9]*[)]? *)'  # 匹配重复次数或格式字段
                       r'(?P<order2>[<>|=]?)'  # 匹配第二个字节顺序标识符(可选)
                       r'(?P<dtype>[A-Za-z0-9.?]*(?:\[[a-zA-Z0-9,.]+\])?)')  # 匹配数据类型描述

# 正则表达式,用于匹配逗号分隔的字符串中的逗号
sep_re = re.compile(r'\s*,\s*')

# 正则表达式,用于匹配字符串末尾的空格
space_re = re.compile(r'\s+$')

# 用于处理等号对应的转换字典
_convorder = {'=': _nbo}

def _commastring(astr):
    # 开始索引初始化为0
    startindex = 0
    # 结果列表
    result = []
    # 是否为列表
    islist = False

    # 当开始索引小于字符串长度时循环
    while startindex < len(astr):
        # 使用 format_re 正则表达式匹配字符串 astr,从 startindex 开始匹配
        mo = format_re.match(astr, pos=startindex)
        try:
            # 尝试解构正则匹配结果为四个部分:order1, repeats, order2, dtype
            (order1, repeats, order2, dtype) = mo.groups()
        except (TypeError, AttributeError):
            # 捕获可能的异常,抛出包含详细信息的 ValueError
            raise ValueError(
                f'format number {len(result)+1} of "{astr}" is not recognized'
                ) from None
        startindex = mo.end()

        # 如果开始索引小于字符串长度
        if startindex < len(astr):
            # 如果是末尾的空格,将开始索引设为字符串长度
            if space_re.match(astr, pos=startindex):
                startindex = len(astr)
            else:
                # 否则尝试使用 sep_re 匹配逗号分隔符
                mo = sep_re.match(astr, pos=startindex)
                if not mo:
                    # 如果不匹配,抛出异常
                    raise ValueError(
                        'format number %d of "%s" is not recognized' %
                        (len(result)+1, astr))
                startindex = mo.end()
                # 设置为列表标记为 True
                islist = True

        # 根据 order1 和 order2 确定顺序标识符 order
        if order2 == '':
            order = order1
        elif order1 == '':
            order = order2
        else:
            # 使用 _convorder 获取对应的顺序标识符,如果不一致则抛出异常
            order1 = _convorder.get(order1, order1)
            order2 = _convorder.get(order2, order2)
            if (order1 != order2):
                raise ValueError(
                    'inconsistent byte-order specification %s and %s' %
                    (order1, order2))
            order = order1

        # 如果顺序标识符为 '|', '=', _nbo 中的一种,则置为空字符串
        if order in ('|', '=', _nbo):
            order = ''
        # 将顺序标识符与 dtype 组合成新的数据类型描述
        dtype = order + dtype

        # 如果 repeats 为空,则新项为 dtype;否则将 repeats 转换为字面量并与 dtype 组合成元组
        if repeats == '':
            newitem = dtype
        else:
            if (repeats[0] == "(" and repeats[-1] == ")"
                    and repeats[1:-1].strip() != ""
                    and "," not in repeats):
                # 警告信息,提示传入的重复次数格式已过时
                warnings.warn(
                    'Passing in a parenthesized single number for repeats '
                    'is deprecated; pass either a single number or indicate '
                    'a tuple with a comma, like "(2,)".', DeprecationWarning,
                    stacklevel=2)
            newitem = (dtype, ast.literal_eval(repeats))

        # 将新项添加到结果列表中
        result.append(newitem)

    # 如果 islist 为 True,返回结果列表;否则返回结果列表的第一个元素
    return result if islist else result[0]

# dummy_ctype 类的定义,用于模拟 C 类型
class dummy_ctype:

    def __init__(self, cls):
        self._cls = cls

    def __mul__(self, other):
        # 乘法运算符重载,返回 self
        return self

    def __call__(self, *other):
        # 调用运算符重载,返回传入参数的类对象
        return self._cls(other)

    def __eq__(self, other):
        # 等于运算符重载,比较两个对象的类是否相等
        return self._cls == other._cls

    def __ne__(self, other):
        # 不等于运算符重载,比较两个对象的类是否不相等
        return self._cls != other._cls

def _getintp_ctype():
    # 获取 _getintp_ctype 的缓存值,如果不为 None 则直接返回
    val = _getintp_ctype.cache
    if val is not None:
        return val
    # 检查 ctypes 是否可用,如果不可用则导入 numpy 并使用 dummy_ctype 处理 np.intp 类型
    if ctypes is None:
        import numpy as np
        val = dummy_ctype(np.intp)
    else:
        # 获取 dtype 对象的字符表示
        char = dtype('n').char
        # 根据字符表示选择对应的 ctypes 类型
        if char == 'i':
            val = ctypes.c_int
        elif char == 'l':
            val = ctypes.c_long
        elif char == 'q':
            val = ctypes.c_longlong
        else:
            val = ctypes.c_long
    # 将确定的 ctypes 类型缓存到 _getintp_ctype.cache 中
    _getintp_ctype.cache = val
    # 返回确定的 ctypes 类型
    return val
# Reset the cache attribute `_getintp_ctype.cache` to None
_getintp_ctype.cache = None

# Define a class `_missing_ctypes` used to emulate ctypes functionality if ctypes is unavailable
class _missing_ctypes:
    # Define a method `cast` that returns the value of `num`
    def cast(self, num, obj):
        return num.value
    
    # Define a nested class `c_void_p` that initializes with a pointer `ptr` and sets `value` attribute to `ptr`
    class c_void_p:
        def __init__(self, ptr):
            self.value = ptr

# Define a class `_ctypes` used for managing ctypes-related operations
class _ctypes:
    # Initialize with an array `array` and optional pointer `ptr`
    def __init__(self, array, ptr=None):
        self._arr = array
        
        # Check if ctypes module is available
        if ctypes:
            self._ctypes = ctypes  # Use standard ctypes if available
            self._data = self._ctypes.c_void_p(ptr)  # Initialize with c_void_p object
        else:
            # Emulate ctypes functionality using `_missing_ctypes` if ctypes is unavailable
            self._ctypes = _missing_ctypes()
            self._data = self._ctypes.c_void_p(ptr)
            self._data._objects = array  # Attach array reference to `_data`

        # Determine if array is zero-dimensional
        if self._arr.ndim == 0:
            self._zerod = True
        else:
            self._zerod = False

    # Method to return data pointer cast to a specified ctypes object `obj`
    def data_as(self, obj):
        """
        Return the data pointer cast to a particular c-types object.
        For example, calling ``self._as_parameter_`` is equivalent to
        ``self.data_as(ctypes.c_void_p)``. Perhaps you want to use
        the data as a pointer to a ctypes array of floating-point data:
        ``self.data_as(ctypes.POINTER(ctypes.c_double))``.

        The returned pointer will keep a reference to the array.
        """
        # Workaround for CPython bug causing circular reference with `_ctypes.cast`
        ptr = self._ctypes.cast(self._data, obj)  # Cast `_data` to `obj`
        ptr._arr = self._arr  # Attach `_arr` to `ptr` to maintain array reference
        return ptr

    # Method to return shape tuple as an array of a specified c-types type `obj`
    def shape_as(self, obj):
        """
        Return the shape tuple as an array of some other c-types
        type. For example: ``self.shape_as(ctypes.c_short)``.
        """
        if self._zerod:
            return None  # Return None if array is zero-dimensional
        return (obj * self._arr.ndim)(*self._arr.shape)  # Create array of shape using `obj`

    # Method to return strides tuple as an array of a specified c-types type `obj`
    def strides_as(self, obj):
        """
        Return the strides tuple as an array of some other
        c-types type. For example: ``self.strides_as(ctypes.c_longlong)``.
        """
        if self._zerod:
            return None  # Return None if array is zero-dimensional
        return (obj * self._arr.ndim)(*self._arr.strides)  # Create array of strides using `obj`

    @property
    def data(self):
        """
        返回数组内存区域的指针作为 Python 整数。
        这个内存区域可能包含未对齐或不正确字节顺序的数据。
        甚至这个内存区域可能是不可写的。
        当将这个属性传递给任意的 C 代码时,应该尊重数组的标志和数据类型,
        以避免可能导致 Python 崩溃的问题。用户注意!
        此属性的值与 `self._array_interface_['data'][0]` 完全相同。

        与 `data_as` 不同,注意不会保留对数组的引用:
        例如 `ctypes.c_void_p((a + b).ctypes.data)` 将导致指向已释放数组的指针,
        应该写作 `(a + b).ctypes.data_as(ctypes.c_void_p)`
        """
        return self._data.value

    @property
    def shape(self):
        """
        (c_intp*self.ndim): 长度为 self.ndim 的 ctypes 数组,
        基本类型是对应于此平台上 `dtype('p')` 的 C 整数(参见 `~numpy.ctypeslib.c_intp`)。
        这个基本类型可能是 `ctypes.c_int`、`ctypes.c_long` 或 `ctypes.c_longlong`,具体取决于平台。
        这个 ctypes 数组包含底层数组的形状信息。
        """
        return self.shape_as(_getintp_ctype())

    @property
    def strides(self):
        """
        (c_intp*self.ndim): 长度为 self.ndim 的 ctypes 数组,
        基本类型与 shape 属性相同。这个 ctypes 数组包含底层数组的跨步信息。
        跨步信息很重要,因为它显示了在数组中跳转到下一个元素需要跳过多少字节。
        """
        return self.strides_as(_getintp_ctype())

    @property
    def _as_parameter_(self):
        """
        覆盖 ctypes 的半神奇方法

        允许 `c_func(some_array.ctypes)`
        """
        return self.data_as(ctypes.c_void_p)

    # Numpy 1.21.0, 2021-05-18

    def get_data(self):
        """已弃用的 `_ctypes.data` 属性的获取器。

        .. deprecated:: 1.21
        """
        warnings.warn('"get_data" 已弃用。请使用 "data"',
                      DeprecationWarning, stacklevel=2)
        return self.data

    def get_shape(self):
        """已弃用的 `_ctypes.shape` 属性的获取器。

        .. deprecated:: 1.21
        """
        warnings.warn('"get_shape" 已弃用。请使用 "shape"',
                      DeprecationWarning, stacklevel=2)
        return self.shape

    def get_strides(self):
        """已弃用的 `_ctypes.strides` 属性的获取器。

        .. deprecated:: 1.21
        """
        warnings.warn('"get_strides" 已弃用。请使用 "strides"',
                      DeprecationWarning, stacklevel=2)
        return self.strides
    # 定义一个方法 `get_as_parameter`,用于获取 `_ctypes._as_parameter_` 属性值。
    # 此方法已弃用,用于返回 `_ctypes._as_parameter_` 属性的值。
    def get_as_parameter(self):
        """Deprecated getter for the `_ctypes._as_parameter_` property.

        .. deprecated:: 1.21
        """
        # 发出警告,提醒使用者方法已弃用,建议使用 `_as_parameter_` 替代
        warnings.warn(
            '"get_as_parameter" is deprecated. Use "_as_parameter_" instead',
            DeprecationWarning, stacklevel=2,
        )
        # 返回 `_ctypes._as_parameter_` 的值
        return self._as_parameter_
# 给定数据类型和排序对象,返回新的字段名元组,按指定顺序排列
def _newnames(datatype, order):
    # 获取旧字段名元组
    oldnames = datatype.names
    # 转换为列表进行操作
    nameslist = list(oldnames)
    # 如果 order 是字符串,转换为列表
    if isinstance(order, str):
        order = [order]
    seen = set()
    # 如果 order 是列表或元组,则遍历处理
    if isinstance(order, (list, tuple)):
        for name in order:
            try:
                nameslist.remove(name)
            except ValueError:
                # 如果字段名重复,抛出异常
                if name in seen:
                    raise ValueError(f"duplicate field name: {name}") from None
                else:
                    raise ValueError(f"unknown field name: {name}") from None
            seen.add(name)
        # 返回按顺序排列后的新字段名元组
        return tuple(list(order) + nameslist)
    # 如果 order 类型不支持,抛出异常
    raise ValueError(f"unsupported order value: {order}")

# 返回结构化数组的副本,移除字段之间的填充字节
def _copy_fields(ary):
    """Return copy of structured array with padding between fields removed.

    Parameters
    ----------
    ary : ndarray
       Structured array from which to remove padding bytes

    Returns
    -------
    ary_copy : ndarray
       Copy of ary with padding bytes removed
    """
    # 获取数组的数据类型
    dt = ary.dtype
    # 创建副本数据类型,包括字段名和格式
    copy_dtype = {'names': dt.names,
                  'formats': [dt.fields[name][0] for name in dt.names]}
    # 返回副本数组,使用副本数据类型,并确保复制数据
    return array(ary, dtype=copy_dtype, copy=True)

# 对两个结构化数据类型执行类型提升
def _promote_fields(dt1, dt2):
    """ Perform type promotion for two structured dtypes.

    Parameters
    ----------
    dt1 : structured dtype
        First dtype.
    dt2 : structured dtype
        Second dtype.

    Returns
    -------
    out : dtype
        The promoted dtype

    Notes
    -----
    If one of the inputs is aligned, the result will be.  The titles of
    both descriptors must match (point to the same field).
    """
    # 必须都是结构化的,并且字段名必须相同且顺序一致
    if (dt1.names is None or dt2.names is None) or dt1.names != dt2.names:
        raise DTypePromotionError(
                f"field names `{dt1.names}` and `{dt2.names}` mismatch.")

    # 如果两者完全相同,则可能可以直接返回相同的数据类型
    identical = dt1 is dt2
    new_fields = []
    for name in dt1.names:
        field1 = dt1.fields[name]
        field2 = dt2.fields[name]
        # 获取提升后的新描述符
        new_descr = promote_types(field1[0], field2[0])
        identical = identical and new_descr is field1[0]

        # 检查标题是否匹配(如果有的话)
        if field1[2:] != field2[2:]:
            raise DTypePromotionError(
                    f"field titles of field '{name}' mismatch")
        # 如果长度为2,则直接添加,否则添加元组(包含标题和字段名)
        if len(field1) == 2:
            new_fields.append((name, new_descr))
        else:
            new_fields.append(((field1[2], name), new_descr))

    # 返回新的数据类型,保持对齐性
    res = dtype(new_fields, align=dt1.isalignedstruct or dt2.isalignedstruct)

    # 如果数据类型完全相同,则保留标识(和元数据)
    # 如果 itemsize 和偏移量也没有修改,则应该保留标识
    # 可能可以加快速度,但也可能完全删除。
    # 如果条件 identical 为真且 res 的元素大小与 dt1 的元素大小相同,则执行以下操作
    if identical and res.itemsize == dt1.itemsize:
        # 遍历 dt1 的字段名
        for name in dt1.names:
            # 如果 dt1 的字段 name 对应的第二个元素类型不等于 res 中相同字段 name 对应的第二个元素类型
            if dt1.fields[name][1] != res.fields[name][1]:
                # 返回 res,表示 dtype 发生了变化。
                return res  # the dtype changed.
        # 如果以上条件都没有触发返回,返回 dt1,表示 dtype 未发生变化。
        return dt1

    # 如果条件不满足,返回 res。
    return res
# 定义一个函数,用于检查对对象数组进行 getfield 操作的安全性
def _getfield_is_safe(oldtype, newtype, offset):
    """ Checks safety of getfield for object arrays.

    As in _view_is_safe, we need to check that memory containing objects is not
    reinterpreted as a non-object datatype and vice versa.

    Parameters
    ----------
    oldtype : data-type
        Data type of the original ndarray.
    newtype : data-type
        Data type of the field being accessed by ndarray.getfield
    offset : int
        Offset of the field being accessed by ndarray.getfield

    Raises
    ------
    TypeError
        If the field access is invalid

    """
    # 检查是否涉及对象类型,如果涉及则进行安全性检查
    if newtype.hasobject or oldtype.hasobject:
        # 如果偏移量为 0 并且新类型与旧类型相同,则返回
        if offset == 0 and newtype == oldtype:
            return
        # 如果旧类型具有命名字段,则遍历每个字段
        if oldtype.names is not None:
            for name in oldtype.names:
                # 检查字段偏移量和类型是否匹配
                if (oldtype.fields[name][1] == offset and
                        oldtype.fields[name][0] == newtype):
                    return
        # 若不满足上述条件,则表示无法进行字段的 get/set 操作,抛出异常
        raise TypeError("Cannot get/set field of an object array")
    return


# 定义一个函数,用于检查涉及对象数组的视图操作的安全性
def _view_is_safe(oldtype, newtype):
    """ Checks safety of a view involving object arrays, for example when
    doing::

        np.zeros(10, dtype=oldtype).view(newtype)

    Parameters
    ----------
    oldtype : data-type
        Data type of original ndarray
    newtype : data-type
        Data type of the view

    Raises
    ------
    TypeError
        If the new type is incompatible with the old type.

    """

    # 若类型相同,则视图操作安全无需检查
    if oldtype == newtype:
        return

    # 若涉及到对象类型,则视图操作不安全,抛出异常
    if newtype.hasobject or oldtype.hasobject:
        raise TypeError("Cannot change data-type for array of references.")
    return


# PEP 3118 格式转换映射表,用于构造 NumPy 的 dtype
_pep3118_native_map = {
    '?': '?',
    'c': 'S1',
    'b': 'b',
    'B': 'B',
    'h': 'h',
    'H': 'H',
    'i': 'i',
    'I': 'I',
    'l': 'l',
    'L': 'L',
    'q': 'q',
    'Q': 'Q',
    'e': 'e',
    'f': 'f',
    'd': 'd',
    'g': 'g',
    'Zf': 'F',
    'Zd': 'D',
    'Zg': 'G',
    's': 'S',
    'w': 'U',
    'O': 'O',
    'x': 'V',  # 填充
}
_pep3118_native_typechars = ''.join(_pep3118_native_map.keys())

# PEP 3118 标准格式转换映射表
_pep3118_standard_map = {
    '?': '?',
    'c': 'S1',
    'b': 'b',
    'B': 'B',
    'h': 'i2',
    'H': 'u2',
    'i': 'i4',
    'I': 'u4',
    'l': 'i4',
    'L': 'u4',
    'q': 'i8',
    'Q': 'u8',
    'e': 'f2',
    'f': 'f',
    'd': 'd',
    'Zf': 'F',
    'Zd': 'D',
    's': 'S',
    'w': 'U',
    'O': 'O',
    'x': 'V',  # 填充
}
_pep3118_standard_typechars = ''.join(_pep3118_standard_map.keys())

# PEP 3118 不支持的格式映射表
_pep3118_unsupported_map = {
    'u': 'UCS-2 strings',
    '&': 'pointers',
    't': 'bitfields',
    'X': 'function pointers',
}

# _Stream 类定义,用于处理字节流
class _Stream:
    def __init__(self, s):
        self.s = s
        self.byteorder = '@'

    # 前进方法,用于从流中读取指定数量的字节并返回
    def advance(self, n):
        res = self.s[:n]
        self.s = self.s[n:]
        return res
    # 检查字符串起始是否与给定字符串 c 匹配,若匹配则消耗相同长度的字符串并返回 True,否则返回 False
    def consume(self, c):
        if self.s[:len(c)] == c:
            self.advance(len(c))  # 消耗与 c 相同长度的字符串
            return True
        return False

    # 消耗当前字符串直到遇到符合条件的字符或函数 c,返回消耗的部分字符串
    def consume_until(self, c):
        if callable(c):  # 如果 c 是可调用对象(函数)
            i = 0
            while i < len(self.s) and not c(self.s[i]):
                i = i + 1  # 查找第一个使得 c 返回 True 的位置
            return self.advance(i)  # 消耗 i 长度的字符串并返回
        else:
            i = self.s.index(c)  # 找到字符串中第一次出现字符 c 的位置
            res = self.advance(i)  # 消耗 i 长度的字符串并返回
            self.advance(len(c))  # 再消耗 c 的长度
            return res

    # 返回当前字符串的第一个字符
    @property
    def next(self):
        return self.s[0]

    # 检查当前字符串是否为真(非空)
    def __bool__(self):
        return bool(self.s)
# 从 PEP3118 规范中解析数据类型,返回解析后的数据类型对象
def _dtype_from_pep3118(spec):
    # 创建一个流对象来处理规范
    stream = _Stream(spec)
    # 调用内部函数来解析 PEP3118 规范,获取数据类型和对齐方式
    dtype, align = __dtype_from_pep3118(stream, is_subdtype=False)
    # 返回解析后的数据类型对象
    return dtype

# 内部函数:从流中解析 PEP3118 规范,返回数据类型和对齐方式
def __dtype_from_pep3118(stream, is_subdtype):
    # 定义字段规范的初始状态
    field_spec = dict(
        names=[],
        formats=[],
        offsets=[],
        itemsize=0
    )
    offset = 0
    common_alignment = 1
    is_padding = False

    # 解析规范
    # 对齐类型的最后额外填充
    if stream.byteorder == '@':
        field_spec['itemsize'] += (-offset) % common_alignment

    # 检查是否为简单的单项类型,如果是则展开它
    if (field_spec['names'] == [None]
            and field_spec['offsets'][0] == 0
            and field_spec['itemsize'] == field_spec['formats'][0].itemsize
            and not is_subdtype):
        ret = field_spec['formats'][0]
    else:
        # 修正字段名称
        _fix_names(field_spec)
        # 创建数据类型对象
        ret = dtype(field_spec)

    # 返回解析后的数据类型对象和通用对齐方式
    return ret, common_alignment

# 修正字段名称函数:将为 None 的字段名称替换为下一个未使用的 f%d 名称
def _fix_names(field_spec):
    names = field_spec['names']
    for i, name in enumerate(names):
        if name is not None:
            continue

        j = 0
        while True:
            name = f'f{j}'
            if name not in names:
                break
            j = j + 1
        names[i] = name

# 在数据类型的末尾注入指定数量的填充字节
def _add_trailing_padding(value, padding):
    if value.fields is None:
        # 创建只包含一个字段的字段规范
        field_spec = dict(
            names=['f0'],
            formats=[value],
            offsets=[0],
            itemsize=value.itemsize
        )
    else:
        # 从现有数据类型中创建字段规范
        fields = value.fields
        names = value.names
        field_spec = dict(
            names=names,
            formats=[fields[name][0] for name in names],
            offsets=[fields[name][1] for name in names],
            itemsize=value.itemsize
        )

    # 增加填充字节到字段规范的 itemsize
    field_spec['itemsize'] += padding
    return dtype(field_spec)

# 计算列表中所有元素的乘积
def _prod(a):
    p = 1
    for x in a:
        p *= x
    return p

# 计算 a 和 b 的最大公约数
def _gcd(a, b):
    """Calculate the greatest common divisor of a and b"""
    while b:
        a, b = b, a % b
    return a

# 计算 a 和 b 的最小公倍数
def _lcm(a, b):
    return a // _gcd(a, b) * b

# 格式化当 __array_ufunc__ 放弃时的错误消息
def array_ufunc_errmsg_formatter(dummy, ufunc, method, *inputs, **kwargs):
    args_string = ', '.join(['{!r}'.format(arg) for arg in inputs] +
                            ['{}={!r}'.format(k, v)
                             for k, v in kwargs.items()])
    args = inputs + kwargs.get('out', ())
    types_string = ', '.join(repr(type(arg).__name__) for arg in args)
    return ('operand type(s) all returned NotImplemented from '
            '__array_ufunc__({!r}, {!r}, {}): {}'
            .format(ufunc, method, args_string, types_string))

# 格式化当 __array_ufunc__ 放弃时的错误消息
def array_function_errmsg_formatter(public_api, types):
    """ Format the error message for when __array_ufunc__ gives up. """
    # 构造函数名,格式化为字符串,包含模块名和函数名
    func_name = '{}.{}'.format(public_api.__module__, public_api.__name__)
    # 返回一条错误消息,指明没有在实现 '__array_function__' 的类型中找到对应函数的实现
    return ("no implementation found for '{}' on types that implement "
            '__array_function__: {}'.format(func_name, list(types)))
# 构建函数签名字符串,类似于 PEP 457 的格式
def _ufunc_doc_signature_formatter(ufunc):
    # 如果输入参数个数为1,则输入参数为 'x'
    if ufunc.nin == 1:
        in_args = 'x'
    else:
        # 否则,输入参数为 'x1, x2, ...' 的格式,根据输入参数个数生成
        in_args = ', '.join(f'x{i+1}' for i in range(ufunc.nin))

    # 输出参数可以是关键字参数或位置参数
    if ufunc.nout == 0:
        out_args = ', /, out=()'
    elif ufunc.nout == 1:
        out_args = ', /, out=None'
    else:
        # 如果有多个输出参数,则输出参数为 '[, out1, out2, ...]' 的格式
        out_args = '[, {positional}], / [, out={default}]'.format(
            positional=', '.join(
                'out{}'.format(i+1) for i in range(ufunc.nout)),
            default=repr((None,)*ufunc.nout)
        )

    # 关键字参数包括一些固定的参数和可变的参数
    kwargs = (
        ", casting='same_kind'"
        ", order='K'"
        ", dtype=None"
        ", subok=True"
    )

    # 注意:gufunc 可能支持 `axis` 参数,也可能不支持
    if ufunc.signature is None:
        kwargs = f", where=True{kwargs}[, signature]"
    else:
        kwargs += "[, signature, axes, axis]"

    # 拼接所有部分成为完整的函数签名字符串
    return '{name}({in_args}{out_args}, *{kwargs})'.format(
        name=ufunc.__name__,
        in_args=in_args,
        out_args=out_args,
        kwargs=kwargs
    )


# 检查一个类是否来自 ctypes,以解决针对这些对象的缓冲区协议中的 bug,参见 bpo-10746
def npy_ctypes_check(cls):
    try:
        # ctypes 类是新式类,因此有 __mro__ 属性。对于具有多重继承的 ctypes 类,这可能失败。
        if IS_PYPY:
            # (..., _ctypes.basics._CData, Bufferable, object)
            ctype_base = cls.__mro__[-3]
        else:
            # # (..., _ctypes._CData, object)
            ctype_base = cls.__mro__[-2]
        # 检查基类是否属于 _ctypes 模块
        return '_ctypes' in ctype_base.__module__
    except Exception:
        # 出现异常时返回 False
        return False


# 用于处理 na_object 参数在 stringdtype 的 C 实现中 __reduce__ 方法的 _NoValue 默认参数
def _convert_to_stringdtype_kwargs(coerce, na_object=_NoValue):
    if na_object is _NoValue:
        # 如果 na_object 是 _NoValue,默认创建一个 StringDType 对象
        return StringDType(coerce=coerce)
    else:
        # 否则,使用指定的 na_object 创建 StringDType 对象
        return StringDType(coerce=coerce, na_object=na_object)

.\numpy\numpy\_core\_internal.pyi

# 从 typing 模块中导入需要的类型:Any(任意类型)、TypeVar(类型变量)、overload(函数重载)、Generic(泛型)
import ctypes as ct

# 从 numpy.typing 模块中导入 NDArray 类型
from numpy.typing import NDArray
# 从 numpy.ctypeslib 模块中导入 c_intp 类型
from numpy.ctypeslib import c_intp

# 创建一个类型变量 _CastT,其上界为 ct._CanCastTo 类型,这是从 ctypes.cast 处复制而来的
_CastT = TypeVar("_CastT", bound=ct._CanCastTo)

# 创建一个类型变量 _CT,其上界为 ct._CData 类型
_CT = TypeVar("_CT", bound=ct._CData)

# 创建一个类型变量 _PT,其上界为 int 类型
_PT = TypeVar("_PT", bound=int)

# 定义一个泛型类 _ctypes,使用了类型变量 _PT
class _ctypes(Generic[_PT]):
    
    # 以下是函数重载的定义,为了不同的输入参数类型返回不同的类型
    @overload
    def __new__(cls, array: NDArray[Any], ptr: None = ...) -> _ctypes[None]: ...
    
    @overload
    def __new__(cls, array: NDArray[Any], ptr: _PT) -> _ctypes[_PT]: ...
    
    # 属性定义:返回 _PT 类型的数据
    @property
    def data(self) -> _PT: ...
    
    # 属性定义:返回 c_intp 类型的数组,表示形状
    @property
    def shape(self) -> ct.Array[c_intp]: ...
    
    # 属性定义:返回 c_intp 类型的数组,表示步幅
    @property
    def strides(self) -> ct.Array[c_intp]: ...
    
    # 属性定义:返回 ct.c_void_p 类型的对象,作为参数使用
    @property
    def _as_parameter_(self) -> ct.c_void_p: ...
    
    # 方法定义:将当前对象转换为 obj 指定的类型 _CastT
    def data_as(self, obj: type[_CastT]) -> _CastT: ...
    
    # 方法定义:将当前对象的形状转换为 obj 指定的类型 _CT 的数组
    def shape_as(self, obj: type[_CT]) -> ct.Array[_CT]: ...
    
    # 方法定义:将当前对象的步幅转换为 obj 指定的类型 _CT 的数组
    def strides_as(self, obj: type[_CT]) -> ct.Array[_CT]: ...

.\numpy\numpy\_core\_machar.py

"""
Machine arithmetic - determine the parameters of the
floating-point arithmetic system

Author: Pearu Peterson, September 2003

"""
# 定义一个列表,包含在 fromnumeric 模块中导出的任何函数或类
__all__ = ['MachAr']

# 从 fromnumeric 模块导入 any 函数
from .fromnumeric import any
# 从 _ufunc_config 模块导入 errstate 函数
from ._ufunc_config import errstate
# 从 .._utils 模块导入 set_module 函数
from .._utils import set_module

# 需要加快速度...特别是对于 longdouble

# 2021-10-20 弃用,NumPy 1.22
class MachAr:
    """
    诊断机器参数。

    Attributes
    ----------
    ibeta : int
        表示数字的基数。
    it : int
        浮点数尾数 M 中基数 `ibeta` 的位数。
    machep : int
        最小(最负)的 `ibeta` 的幂的指数,加到 1.0 上会得到与 1.0 不同的结果。
    eps : float
        浮点数 ``beta**machep``(浮点精度)。
    negep : int
        最小的 `ibeta` 的幂的指数,从 1.0 减去会得到与 1.0 不同的结果。
    epsneg : float
        浮点数 ``beta**negep``。
    iexp : int
        指数中的位数(包括其符号和偏置)。
    minexp : int
        与尾数中没有前导零一致的最小(最负)的 `ibeta` 的幂。
    xmin : float
        浮点数 ``beta**minexp``(具有完整精度的最小正浮点数)。
    maxexp : int
        导致溢出的最小(正)的 `ibeta` 的幂。
    xmax : float
        ``(1-epsneg) * beta**maxexp``(可用的最大(按数量级)浮点值)。
    irnd : int
        在 ``range(6)`` 中,有关舍入方式和如何处理下溢的信息。
    ngrd : int
        在截断两个尾数以适应表示时使用的“保护位”数量。
    epsilon : float
        与 `eps` 相同。
    tiny : float
        `smallest_normal` 的别名,保持向后兼容性。
    huge : float
        与 `xmax` 相同。
    precision : float
        ``- int(-log10(eps))``
    resolution : float
        ``- 10**(-precision)``
    smallest_normal : float
        遵循 IEEE-754 标准,在尾数中有 1 作为首位的最小正浮点数。与 `xmin` 相同。
    smallest_subnormal : float
        遵循 IEEE-754 标准,在尾数中有 0 作为首位的最小正浮点数。

    Parameters
    ----------
    float_conv : function, optional
        将整数或整数数组转换为浮点数或浮点数数组的函数。默认为 `float`。
    int_conv : function, optional
        将浮点数或浮点数数组转换为整数或整数数组的函数。默认为 `int`。
    float_to_float : function, optional
        将浮点数数组转换为浮点数的函数。默认为 `float`。
        注意,在当前实现中,这似乎没有任何有用的作用。
    def __init__(self, float_conv=float, int_conv=int,
                 float_to_float=float,
                 float_to_str=lambda v:'%24.16e' % v,
                 title='Python floating point number'):
        """
        初始化函数,用于创建一个 MachAr 对象。

        Parameters:
        ----------
        float_conv : function, optional
            用于将整数转换为浮点数的函数(数组)。默认为 `float`。
        int_conv : function, optional
            用于将浮点数(数组)转换为整数的函数。默认为 `int`。
        float_to_float : function, optional
            用于将浮点数数组转换为浮点数的函数。默认为 `float`。
        float_to_str : function, optional
            用于将浮点数数组转换为字符串的函数。默认为 lambda 函数 `lambda v:'%24.16e' % v`。
        title : str, optional
            MachAr 对象的标题,将在其字符串表示中打印出来。默认为 'Python floating point number'"""
        # 在此处忽略所有错误,因为我们有意触发下溢以检测运行架构的特性。
        with errstate(under='ignore'):
            # 调用内部方法 `_do_init` 进行初始化设置
            self._do_init(float_conv, int_conv, float_to_float, float_to_str, title)

    def __str__(self):
        """
        返回 MachAr 对象的字符串表示形式。

        Returns:
        -------
        str
            MachAr 对象的字符串表示形式,包含各种机器参数的详细信息。
        """
        # 定义格式化字符串模板
        fmt = (
           'Machine parameters for %(title)s\n'
           '---------------------------------------------------------------------\n'
           'ibeta=%(ibeta)s it=%(it)s iexp=%(iexp)s ngrd=%(ngrd)s irnd=%(irnd)s\n'
           'machep=%(machep)s     eps=%(_str_eps)s (beta**machep == epsilon)\n'
           'negep =%(negep)s  epsneg=%(_str_epsneg)s (beta**epsneg)\n'
           'minexp=%(minexp)s   xmin=%(_str_xmin)s (beta**minexp == tiny)\n'
           'maxexp=%(maxexp)s    xmax=%(_str_xmax)s ((1-epsneg)*beta**maxexp == huge)\n'
           'smallest_normal=%(smallest_normal)s    '
           'smallest_subnormal=%(smallest_subnormal)s\n'
           '---------------------------------------------------------------------\n'
           )
        # 使用格式化字符串和对象的属性字典返回字符串表示形式
        return fmt % self.__dict__
# 如果当前脚本作为主程序执行(而不是被导入到其他模块),则执行以下代码块
if __name__ == '__main__':
    # 打印调用 MachAr() 函数的结果
    print(MachAr())

.\numpy\numpy\_core\_methods.py

"""
Array methods which are called by both the C-code for the method
and the Python code for the NumPy-namespace function

"""
# 导入所需模块
import os  # 导入操作系统模块
import pickle  # 导入pickle模块,用于对象序列化和反序列化
import warnings  # 导入警告模块,用于处理警告信息
from contextlib import nullcontext  # 导入上下文管理器nullcontext

# 导入NumPy的核心模块
from numpy._core import multiarray as mu  # 导入NumPy的multiarray模块并重命名为mu
from numpy._core import umath as um  # 导入NumPy的umath模块并重命名为um
from numpy._core.multiarray import asanyarray  # 导入asanyarray函数
from numpy._core import numerictypes as nt  # 导入numerictypes模块并重命名为nt
from numpy._core import _exceptions  # 导入异常处理模块_exceptions
from numpy._core._ufunc_config import _no_nep50_warning  # 导入_ufunc_config模块中的_no_nep50_warning
from numpy._globals import _NoValue  # 导入_NoValue对象

# save those O(100) nanoseconds!
bool_dt = mu.dtype("bool")  # 创建布尔类型的数据类型对象bool_dt
umr_maximum = um.maximum.reduce  # 将um模块的maximum.reduce方法赋值给umr_maximum
umr_minimum = um.minimum.reduce  # 将um模块的minimum.reduce方法赋值给umr_minimum
umr_sum = um.add.reduce  # 将um模块的add.reduce方法赋值给umr_sum
umr_prod = um.multiply.reduce  # 将um模块的multiply.reduce方法赋值给umr_prod
umr_bitwise_count = um.bitwise_count  # 将um模块的bitwise_count方法赋值给umr_bitwise_count
umr_any = um.logical_or.reduce  # 将um模块的logical_or.reduce方法赋值给umr_any
umr_all = um.logical_and.reduce  # 将um模块的logical_and.reduce方法赋值给umr_all

# Complex types to -> (2,)float view for fast-path computation in _var()
_complex_to_float = {
    nt.dtype(nt.csingle) : nt.dtype(nt.single),  # 将csingle对应的数据类型映射为single
    nt.dtype(nt.cdouble) : nt.dtype(nt.double),  # 将cdouble对应的数据类型映射为double
}
# Special case for windows: ensure double takes precedence
if nt.dtype(nt.longdouble) != nt.dtype(nt.double):
    _complex_to_float.update({
        nt.dtype(nt.clongdouble) : nt.dtype(nt.longdouble),  # 将clongdouble对应的数据类型映射为longdouble
    })

# avoid keyword arguments to speed up parsing, saves about 15%-20% for very
# small reductions
# 定义_amax函数,实现对数组的最大值计算
def _amax(a, axis=None, out=None, keepdims=False,
          initial=_NoValue, where=True):
    return umr_maximum(a, axis, None, out, keepdims, initial, where)

# 定义_amin函数,实现对数组的最小值计算
def _amin(a, axis=None, out=None, keepdims=False,
          initial=_NoValue, where=True):
    return umr_minimum(a, axis, None, out, keepdims, initial, where)

# 定义_sum函数,实现对数组元素求和
def _sum(a, axis=None, dtype=None, out=None, keepdims=False,
         initial=_NoValue, where=True):
    return umr_sum(a, axis, dtype, out, keepdims, initial, where)

# 定义_prod函数,实现对数组元素求积
def _prod(a, axis=None, dtype=None, out=None, keepdims=False,
          initial=_NoValue, where=True):
    return umr_prod(a, axis, dtype, out, keepdims, initial, where)

# 定义_any函数,实现对数组中是否有True值的判断
def _any(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
    # 默认情况下,对于_any和_all函数,返回布尔值
    if dtype is None:
        dtype = bool_dt
    # 目前解析关键字参数的速度相对较慢,因此暂时避免使用它
    if where is True:
        return umr_any(a, axis, dtype, out, keepdims)
    return umr_any(a, axis, dtype, out, keepdims, where=where)

# 定义_all函数,实现对数组中所有元素是否为True的判断
def _all(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
    # 默认情况下,对于_any和_all函数,返回布尔值
    if dtype is None:
        dtype = bool_dt
    # 目前解析关键字参数的速度相对较慢,因此暂时避免使用它
    if where is True:
        return umr_all(a, axis, dtype, out, keepdims)
    return umr_all(a, axis, dtype, out, keepdims, where=where)

# 定义_count_reduce_items函数,用于快速处理默认情况的数组减少操作
def _count_reduce_items(arr, axis, keepdims=False, where=True):
    # fast-path for the default case
    # 默认情况的快速处理路径
    # 如果 where 参数为 True,则计算项目数量而不考虑布尔掩码
    if where is True:
        # 如果没有指定 axis 参数,则默认为数组的所有维度
        if axis is None:
            axis = tuple(range(arr.ndim))
        # 如果 axis 不是元组,则转换为元组
        elif not isinstance(axis, tuple):
            axis = (axis,)
        # 计算项目数量的初始值为 1
        items = 1
        # 遍历所有指定的 axis 维度,计算项目数量
        for ax in axis:
            items *= arr.shape[mu.normalize_axis_index(ax, arr.ndim)]
        # 将 items 转换为 numpy 的整数类型
        items = nt.intp(items)
    else:
        # TODO: 优化当 `where` 沿着非约简轴进行广播时的情况,
        # 并且完整求和超出所需的范围。

        # 导入 broadcast_to 函数来保护循环导入问题
        from numpy.lib._stride_tricks_impl import broadcast_to
        # 计算布尔掩码中 True 值的数量(可能进行了广播)
        items = umr_sum(broadcast_to(where, arr.shape), axis, nt.intp, None,
                        keepdims)
    # 返回计算得到的项目数量
    return items
# 定义一个函数,用于对数组进行剪裁操作,限制其数值在给定范围内
def _clip(a, min=None, max=None, out=None, **kwargs):
    # 如果未同时给定最小值和最大值,则抛出数值错误
    if min is None and max is None:
        raise ValueError("One of max or min must be given")

    # 如果只给定最大值,则调用 um.minimum 函数进行剪裁
    if min is None:
        return um.minimum(a, max, out=out, **kwargs)
    # 如果只给定最小值,则调用 um.maximum 函数进行剪裁
    elif max is None:
        return um.maximum(a, min, out=out, **kwargs)
    # 如果同时给定最小值和最大值,则调用 um.clip 函数进行剪裁
    else:
        return um.clip(a, min, max, out=out, **kwargs)

# 定义一个函数,计算数组的均值
def _mean(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
    # 将输入数组转换为通用数组类型
    arr = asanyarray(a)

    # 初始化是否得到 float16 结果的标志
    is_float16_result = False

    # 计算在指定轴向上进行均值计算的有效元素数
    rcount = _count_reduce_items(arr, axis, keepdims=keepdims, where=where)
    # 如果计数为零(根据 where 参数),则发出警告
    if rcount == 0 if where is True else umr_any(rcount == 0, axis=None):
        warnings.warn("Mean of empty slice.", RuntimeWarning, stacklevel=2)

    # 如果未指定输出数据类型,则根据输入数组的类型确定默认类型
    if dtype is None:
        if issubclass(arr.dtype.type, (nt.integer, nt.bool)):
            dtype = mu.dtype('f8')  # 整数和布尔型转换为 float64
        elif issubclass(arr.dtype.type, nt.float16):
            dtype = mu.dtype('f4')  # float16 转换为 float32
            is_float16_result = True

    # 计算数组在指定轴向上的总和
    ret = umr_sum(arr, axis, dtype, out, keepdims, where=where)
    # 如果返回结果为 ndarray 类型,则进行除法操作
    if isinstance(ret, mu.ndarray):
        with _no_nep50_warning():
            ret = um.true_divide(
                    ret, rcount, out=ret, casting='unsafe', subok=False)
        # 如果结果为 float16 类型且未指定输出,则转换为原数组的类型
        if is_float16_result and out is None:
            ret = arr.dtype.type(ret)
    # 如果返回结果具有 dtype 属性,则进行除法操作
    elif hasattr(ret, 'dtype'):
        if is_float16_result:
            ret = arr.dtype.type(ret / rcount)
        else:
            ret = ret.dtype.type(ret / rcount)
    # 否则直接进行除法操作
    else:
        ret = ret / rcount

    # 返回计算得到的均值结果
    return ret

# 定义一个函数,计算数组的方差
def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *,
         where=True, mean=None):
    # 将输入数组转换为通用数组类型
    arr = asanyarray(a)

    # 计算在指定轴向上进行计算的有效元素数
    rcount = _count_reduce_items(arr, axis, keepdims=keepdims, where=where)
    # 如果自由度小于等于零(根据 where 参数),则发出警告
    if ddof >= rcount if where is True else umr_any(ddof >= rcount, axis=None):
        warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning,
                      stacklevel=2)

    # 如果未指定输出数据类型且输入数组为整数或布尔类型,则将其转换为 float64 类型
    if dtype is None and issubclass(arr.dtype.type, (nt.integer, nt.bool)):
        dtype = mu.dtype('f8')

    # 如果给定均值参数,则使用该均值参数作为均值
    if mean is not None:
        arrmean = mean
    else:
        # 计算均值。
        # 需要注意的是,如果 dtype 不是浮点类型,则 arraymean 也不会是浮点类型。
        arrmean = umr_sum(arr, axis, dtype, keepdims=True, where=where)
        # rcount 的形状必须与 arrmean 匹配,以便在广播中不改变输出的形状。否则,不能将其存回到 arrmean。
        if rcount.ndim == 0:
            # 默认情况的快速路径,当 where 参数为 True 时
            div = rcount
        else:
            # 当 where 参数作为数组指定时,将 rcount 的形状匹配到 arrmean
            div = rcount.reshape(arrmean.shape)
        if isinstance(arrmean, mu.ndarray):
            with _no_nep50_warning():
                arrmean = um.true_divide(arrmean, div, out=arrmean,
                                         casting='unsafe', subok=False)
        elif hasattr(arrmean, "dtype"):
            arrmean = arrmean.dtype.type(arrmean / rcount)
        else:
            arrmean = arrmean / rcount

    # 计算相对于均值的平方偏差的总和
    # 需要注意 x 可能不是浮点数,并且我们需要它是一个数组,而不是一个标量。
    x = asanyarray(arr - arrmean)

    if issubclass(arr.dtype.type, (nt.floating, nt.integer)):
        x = um.multiply(x, x, out=x)
    # 内置复数类型的快速路径
    elif x.dtype in _complex_to_float:
        xv = x.view(dtype=(_complex_to_float[x.dtype], (2,)))
        um.multiply(xv, xv, out=xv)
        x = um.add(xv[..., 0], xv[..., 1], out=x.real).real
    # 最一般的情况;包括处理包含虚数和具有非本机字节顺序的复杂类型的对象数组
    else:
        x = um.multiply(x, um.conjugate(x), out=x).real

    ret = umr_sum(x, axis, dtype, out, keepdims=keepdims, where=where)

    # 计算自由度并确保其非负。
    rcount = um.maximum(rcount - ddof, 0)

    # 除以自由度
    if isinstance(ret, mu.ndarray):
        with _no_nep50_warning():
            ret = um.true_divide(
                    ret, rcount, out=ret, casting='unsafe', subok=False)
    elif hasattr(ret, 'dtype'):
        ret = ret.dtype.type(ret / rcount)
    else:
        ret = ret / rcount

    return ret
# 计算标准差的函数
def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *,
         where=True, mean=None):
    # 调用 _var 函数计算方差,并返回结果
    ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
               keepdims=keepdims, where=where, mean=mean)

    # 如果 ret 是 mu.ndarray 类型的实例
    if isinstance(ret, mu.ndarray):
        # 对 ret 进行平方根运算,并将结果存储在 ret 中
        ret = um.sqrt(ret, out=ret)
    # 如果 ret 具有 'dtype' 属性
    elif hasattr(ret, 'dtype'):
        # 以 ret.dtype.type 类型对 ret 进行平方根运算,并将结果存储在 ret 中
        ret = ret.dtype.type(um.sqrt(ret))
    else:
        # 否则直接对 ret 进行平方根运算,并将结果存储在 ret 中
        ret = um.sqrt(ret)

    # 返回计算得到的标准差
    return ret

# 计算数组沿指定轴的峰值到峰值(peak-to-peak)值的函数
def _ptp(a, axis=None, out=None, keepdims=False):
    # 计算数组沿指定轴的最大值与最小值之差,并返回结果
    return um.subtract(
        umr_maximum(a, axis, None, out, keepdims),
        umr_minimum(a, axis, None, None, keepdims),
        out
    )

# 将对象序列化到文件中的函数
def _dump(self, file, protocol=2):
    # 如果 file 具有 'write' 方法,则使用 nullcontext 封装 file
    if hasattr(file, 'write'):
        ctx = nullcontext(file)
    else:
        # 否则打开 file 并以二进制写模式进行操作,并使用 nullcontext 封装打开的文件对象
        ctx = open(os.fspath(file), "wb")
    # 使用 nullcontext 上下文管理器打开文件,并使用 pickle.dump 将 self 对象序列化到文件中
    with ctx as f:
        pickle.dump(self, f, protocol=protocol)

# 将对象序列化到字节流中的函数
def _dumps(self, protocol=2):
    # 使用 pickle.dumps 将 self 对象序列化为字节流,并返回结果
    return pickle.dumps(self, protocol=protocol)

# 对数组进行位运算计数的函数
def _bitwise_count(a, out=None, *, where=True, casting='same_kind',
          order='K', dtype=None, subok=True):
    # 调用 umr_bitwise_count 函数对数组进行位运算计数,并返回结果
    return umr_bitwise_count(a, out, where=where, casting=casting,
            order=order, dtype=dtype, subok=subok)

.\numpy\numpy\_core\_string_helpers.py

"""
String-handling utilities to avoid locale-dependence.

Used primarily to generate type name aliases.
"""

# "import string" is costly to import!
# 直接构建翻译表格以避免依赖于 locale
#   "A" = chr(65), "a" = chr(97)
_all_chars = tuple(map(chr, range(256)))
# 构建 ASCII 大写字母翻译表
_ascii_upper = _all_chars[65:65+26]
# 构建 ASCII 小写字母翻译表
_ascii_lower = _all_chars[97:97+26]
# 构建小写字母转换表,包含所有字符
LOWER_TABLE = _all_chars[:65] + _ascii_lower + _all_chars[65+26:]
# 构建大写字母转换表,包含所有字符
UPPER_TABLE = _all_chars[:97] + _ascii_upper + _all_chars[97+26:]


def english_lower(s):
    """ Apply English case rules to convert ASCII strings to all lower case.

    This is an internal utility function to replace calls to str.lower() such
    that we can avoid changing behavior with changing locales. In particular,
    Turkish has distinct dotted and dotless variants of the Latin letter "I" in
    both lowercase and uppercase. Thus, "I".lower() != "i" in a "tr" locale.

    Parameters
    ----------
    s : str

    Returns
    -------
    lowered : str

    Examples
    --------
    >>> from numpy._core.numerictypes import english_lower
    >>> english_lower('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_')
    'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789_'
    >>> english_lower('')
    ''
    """
    # 使用 LOWER_TABLE 翻译表转换字符串为小写
    lowered = s.translate(LOWER_TABLE)
    return lowered


def english_upper(s):
    """ Apply English case rules to convert ASCII strings to all upper case.

    This is an internal utility function to replace calls to str.upper() such
    that we can avoid changing behavior with changing locales. In particular,
    Turkish has distinct dotted and dotless variants of the Latin letter "I" in
    both lowercase and uppercase. Thus, "i".upper() != "I" in a "tr" locale.

    Parameters
    ----------
    s : str

    Returns
    -------
    uppered : str

    Examples
    --------
    >>> from numpy._core.numerictypes import english_upper
    >>> english_upper('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_')
    'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
    >>> english_upper('')
    ''
    """
    # 使用 UPPER_TABLE 翻译表转换字符串为大写
    uppered = s.translate(UPPER_TABLE)
    return uppered


def english_capitalize(s):
    """ Apply English case rules to convert the first character of an ASCII
    string to upper case.

    This is an internal utility function to replace calls to str.capitalize()
    such that we can avoid changing behavior with changing locales.

    Parameters
    ----------
    s : str

    Returns
    -------
    capitalized : str

    Examples
    --------
    >>> from numpy._core.numerictypes import english_capitalize
    >>> english_capitalize('int8')
    'Int8'
    >>> english_capitalize('Int8')
    'Int8'
    >>> english_capitalize('')
    ''
    """
    if s:
        # 首字母大写后与原字符串其余部分拼接
        return english_upper(s[0]) + s[1:]
    else:
        return s

.\numpy\numpy\_core\_type_aliases.py

"""
Due to compatibility, numpy has a very large number of different naming
conventions for the scalar types (those subclassing from `numpy.generic`).
This file produces a convoluted set of dictionaries mapping names to types,
and sometimes other mappings too.

.. data:: allTypes
    A dictionary of names to types that will be exposed as attributes through
    ``np._core.numerictypes.*``

.. data:: sctypeDict
    Similar to `allTypes`, but maps a broader set of aliases to their types.

.. data:: sctypes
    A dictionary keyed by a "type group" string, providing a list of types
    under that group.

"""

import numpy._core.multiarray as ma  # 导入numpy的multiarray模块,并简称为ma
from numpy._core.multiarray import typeinfo, dtype  # 从numpy的multiarray模块导入typeinfo和dtype

######################################
# Building `sctypeDict` and `allTypes`
######################################

sctypeDict = {}  # 初始化空字典sctypeDict,用于存储类型别名到类型的映射
allTypes = {}    # 初始化空字典allTypes,用于存储类型名称到类型的映射
c_names_dict = {}  # 初始化空字典c_names_dict,用于存储C语言类型名称到类型的映射

_abstract_type_names = {  # 抽象类型名称的集合
    "generic", "integer", "inexact", "floating", "number",
    "flexible", "character", "complexfloating", "unsignedinteger",
    "signedinteger"
}

for _abstract_type_name in _abstract_type_names:
    allTypes[_abstract_type_name] = getattr(ma, _abstract_type_name)  # 将抽象类型名映射为numpy.ma中对应的类型对象

for k, v in typeinfo.items():
    if k.startswith("NPY_") and v not in c_names_dict:
        c_names_dict[k[4:]] = v  # 将去掉前缀"NPY_"后的名称作为键,类型对象作为值,存入c_names_dict
    else:
        concrete_type = v.type
        allTypes[k] = concrete_type  # 将typeinfo中的键(类型名称)映射为其对应的具体类型
        sctypeDict[k] = concrete_type  # 同时将其映射存入sctypeDict

_aliases = {
    "double": "float64",
    "cdouble": "complex128",
    "single": "float32",
    "csingle": "complex64",
    "half": "float16",
    "bool_": "bool",
    # Default integer:
    "int_": "intp",
    "uint": "uintp",
}

for k, v in _aliases.items():
    sctypeDict[k] = allTypes[v]  # 将_aliases中的键(类型别名)映射为allTypes中对应的类型,并存入sctypeDict
    allTypes[k] = allTypes[v]    # 同时将其映射存入allTypes

# extra aliases are added only to `sctypeDict`
# to support dtype name access, such as`np.dtype("float")`
_extra_aliases = {  
    "float": "float64",
    "complex": "complex128",
    "object": "object_",
    "bytes": "bytes_",
    "a": "bytes_",
    "int": "int_",
    "str": "str_",
    "unicode": "str_",
}

for k, v in _extra_aliases.items():
    sctypeDict[k] = allTypes[v]  # 将_extra_aliases中的键(类型别名)映射为allTypes中对应的类型,并存入sctypeDict

# include extended precision sized aliases
for is_complex, full_name in [(False, "longdouble"), (True, "clongdouble")]:
    longdouble_type: type = allTypes[full_name]

    bits: int = dtype(longdouble_type).itemsize * 8
    base_name: str = "complex" if is_complex else "float"
    extended_prec_name: str = f"{base_name}{bits}"
    if extended_prec_name not in allTypes:
        sctypeDict[extended_prec_name] = longdouble_type  # 将扩展精度类型名称映射为longdouble_type,并存入sctypeDict
        allTypes[extended_prec_name] = longdouble_type    # 同时将其映射存入allTypes


####################
# Building `sctypes`
####################

sctypes = {"int": set(), "uint": set(), "float": set(),
           "complex": set(), "others": set()}  # 初始化sctypes字典,包含各类类型的空集合

for type_info in typeinfo.values():
    if type_info.kind in ["M", "m"]:  # 排除timedelta和datetime类型
        continue

    concrete_type = type_info.type

    # find proper group for each concrete type
    # 为每种具体类型找到适当的类型组
    # 对于每个类型分组和抽象类型的组合,依次进行迭代
    for type_group, abstract_type in [
        ("int", ma.signedinteger), ("uint", ma.unsignedinteger), 
        ("float", ma.floating), ("complex", ma.complexfloating), 
        ("others", ma.generic)
    ]:
        # 检查具体类型是否是抽象类型的子类
        if issubclass(concrete_type, abstract_type):
            # 如果是,则将具体类型添加到相应类型分组的集合中
            sctypes[type_group].add(concrete_type)
            # 一旦找到匹配,就退出循环
            break
# 对 sctype groups 按照位大小进行排序

# 遍历 sctypes 字典的键(sctype_key),表示不同的数据类型组
for sctype_key in sctypes.keys():
    # 将 sctype_key 对应的值转换为列表,并进行排序
    sctype_list = list(sctypes[sctype_key])
    # 使用 lambda 函数作为排序的关键字,按照 dtype(x).itemsize 的大小排序
    sctype_list.sort(key=lambda x: dtype(x).itemsize)
    # 更新 sctype_key 对应的值为排序后的列表
    sctypes[sctype_key] = sctype_list

.\numpy\numpy\_core\_type_aliases.pyi

# 导入 numpy 库中的 generic 类型
from numpy import generic

# 定义一个类型为 dict 的变量 sctypeDict,键类型为 int 或 str,值类型为 numpy 的 generic 类型
sctypeDict: dict[int | str, type[generic]]

.\numpy\numpy\_core\_ufunc_config.py

"""
Functions for changing global ufunc configuration

This provides helpers which wrap `_get_extobj_dict` and `_make_extobj`, and
`_extobj_contextvar` from umath.
"""
import collections.abc  # 导入 collections.abc 模块
import contextlib  # 导入 contextlib 模块
import contextvars  # 导入 contextvars 模块
import functools  # 导入 functools 模块

from .._utils import set_module  # 从上层模块的 _utils 中导入 set_module 函数
from .umath import _make_extobj, _get_extobj_dict, _extobj_contextvar  # 从 umath 模块导入 _make_extobj, _get_extobj_dict, _extobj_contextvar

__all__ = [
    "seterr", "geterr", "setbufsize", "getbufsize", "seterrcall", "geterrcall",
    "errstate", '_no_nep50_warning'
]  # 公开的模块接口列表

@set_module('numpy')
def seterr(all=None, divide=None, over=None, under=None, invalid=None):
    """
    Set how floating-point errors are handled.

    Note that operations on integer scalar types (such as `int16`) are
    handled like floating point, and are affected by these settings.

    Parameters
    ----------
    all : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
        Set treatment for all types of floating-point errors at once:

        - ignore: Take no action when the exception occurs.
        - warn: Print a :exc:`RuntimeWarning` (via the Python `warnings`
          module).
        - raise: Raise a :exc:`FloatingPointError`.
        - call: Call a function specified using the `seterrcall` function.
        - print: Print a warning directly to ``stdout``.
        - log: Record error in a Log object specified by `seterrcall`.

        The default is not to change the current behavior.
    divide : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
        Treatment for division by zero.
    over : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
        Treatment for floating-point overflow.
    under : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
        Treatment for floating-point underflow.
    invalid : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
        Treatment for invalid floating-point operation.

    Returns
    -------
    old_settings : dict
        Dictionary containing the old settings.

    See also
    --------
    seterrcall : Set a callback function for the 'call' mode.
    geterr, geterrcall, errstate

    Notes
    -----
    The floating-point exceptions are defined in the IEEE 754 standard [1]_:

    - Division by zero: infinite result obtained from finite numbers.
    - Overflow: result too large to be expressed.
    - Underflow: result so close to zero that some precision
      was lost.
    - Invalid operation: result is not an expressible number, typically
      indicates that a NaN was produced.

    .. [1] https://en.wikipedia.org/wiki/IEEE_754

    Examples
    --------
    >>> orig_settings = np.seterr(all='ignore')  # seterr to known value
    >>> np.int16(32000) * np.int16(3)
    30464
    >>> np.seterr(over='raise')
    {'divide': 'ignore', 'over': 'ignore', 'under': 'ignore', 'invalid': 'ignore'}
    >>> old_settings = np.seterr(all='warn', over='raise')
    >>> np.int16(32000) * np.int16(3)
    """
    # 根据传入的参数设置浮点数错误的处理方式,并返回旧的设置
    old_settings = _get_extobj_dict()  # 获取当前的异常处理设置
    new_settings = {}  # 初始化一个空字典,用于存储新的异常处理设置

    if all is not None:
        new_settings['all'] = _make_extobj(all)  # 根据 all 参数设置所有类型异常处理方式

    if divide is not None:
        new_settings['divide'] = _make_extobj(divide)  # 根据 divide 参数设置除法异常处理方式

    if over is not None:
        new_settings['over'] = _make_extobj(over)  # 根据 over 参数设置溢出异常处理方式

    if under is not None:
        new_settings['under'] = _make_extobj(under)  # 根据 under 参数设置下溢异常处理方式

    if invalid is not None:
        new_settings['invalid'] = _make_extobj(invalid)  # 根据 invalid 参数设置无效操作异常处理方式

    _extobj_contextvar.set(new_settings)  # 使用 contextvar 设置新的异常处理方式

    return old_settings  # 返回旧的异常处理设置
    # 引发的异常通常是由于浮点数溢出而导致的乘法操作错误
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    FloatingPointError: overflow encountered in scalar multiply
    
    # 设置 NumPy 库的错误处理方式为打印所有错误
    >>> old_settings = np.seterr(all='print')
    # 获取当前的 NumPy 错误处理设置
    >>> np.geterr()
    {'divide': 'print', 'over': 'print', 'under': 'print', 'invalid': 'print'}
    # 对两个 int16 类型的数进行乘法运算,结果为 30464
    >>> np.int16(32000) * np.int16(3)
    30464
    # 恢复原始的 NumPy 错误处理设置
    >>> np.seterr(**orig_settings)  # restore original
    {'divide': 'print', 'over': 'print', 'under': 'print', 'invalid': 'print'}
    
    """
    # 获取当前的扩展对象字典
    old = _get_extobj_dict()
    # 从字典中移除键为 "call" 和 "bufsize" 的项,如果存在的话
    # 这些项在错误状态对象中并不存在,因此需要移除
    old.pop("call", None)
    old.pop("bufsize", None)
    
    # 使用指定的错误处理设置创建扩展对象
    extobj = _make_extobj(
            all=all, divide=divide, over=over, under=under, invalid=invalid)
    # 将新创建的扩展对象设置为当前的上下文变量
    _extobj_contextvar.set(extobj)
    # 返回修改后的扩展对象字典
    return old
@set_module('numpy')
def geterr():
    """
    Get the current way of handling floating-point errors.

    Returns
    -------
    res : dict
        A dictionary with keys "divide", "over", "under", and "invalid",
        whose values are from the strings "ignore", "print", "log", "warn",
        "raise", and "call". The keys represent possible floating-point
        exceptions, and the values define how these exceptions are handled.

    See Also
    --------
    geterrcall, seterr, seterrcall

    Notes
    -----
    For complete documentation of the types of floating-point exceptions and
    treatment options, see `seterr`.

    Examples
    --------
    >>> np.geterr()
    {'divide': 'warn', 'over': 'warn', 'under': 'ignore', 'invalid': 'warn'}
    >>> np.arange(3.) / np.arange(3.)  # doctest: +SKIP
    array([nan,  1.,  1.])
    RuntimeWarning: invalid value encountered in divide

    >>> oldsettings = np.seterr(all='warn', invalid='raise')
    >>> np.geterr()
    {'divide': 'warn', 'over': 'warn', 'under': 'warn', 'invalid': 'raise'}
    >>> np.arange(3.) / np.arange(3.)
    Traceback (most recent call last):
      ...
    FloatingPointError: invalid value encountered in divide
    >>> oldsettings = np.seterr(**oldsettings)  # restore original

    """
    # Retrieve the current error handling settings as a dictionary
    res = _get_extobj_dict()
    # Remove the entries for "call" and "bufsize" from the dictionary
    res.pop("call", None)
    res.pop("bufsize", None)
    return res


@set_module('numpy')
def setbufsize(size):
    """
    Set the size of the buffer used in ufuncs.

    .. versionchanged:: 2.0
        The scope of setting the buffer is tied to the `numpy.errstate`
        context.  Exiting a ``with errstate():`` will also restore the bufsize.

    Parameters
    ----------
    size : int
        Size of buffer.

    Returns
    -------
    bufsize : int
        Previous size of ufunc buffer in bytes.

    Examples
    --------
    When exiting a `numpy.errstate` context manager the bufsize is restored:

    >>> with np.errstate():
    ...     np.setbufsize(4096)
    ...     print(np.getbufsize())
    ...
    8192
    4096
    >>> np.getbufsize()
    8192

    """
    # Retrieve the current bufsize setting
    old = _get_extobj_dict()["bufsize"]
    # Create a new extended object with the specified bufsize
    extobj = _make_extobj(bufsize=size)
    # Set the new extended object using context variables
    _extobj_contextvar.set(extobj)
    return old


@set_module('numpy')
def getbufsize():
    """
    Return the size of the buffer used in ufuncs.

    Returns
    -------
    getbufsize : int
        Size of ufunc buffer in bytes.

    Examples
    --------
    >>> np.getbufsize()
    8192

    """
    # Retrieve and return the current bufsize from the extended object
    return _get_extobj_dict()["bufsize"]


@set_module('numpy')
def seterrcall(func):
    """
    Set the floating-point error callback function or log object.

    There are two ways to capture floating-point error messages.  The first
    is to set the error-handler to 'call', using `seterr`.  Then, set
    the function to call using this function.

    The second is to set the error-handler to 'log', using `seterr`.

    """
    # This function is intended to set the error callback function or log object,
    # but the actual implementation details are not provided in this excerpt.
    """
    Floating-point errors then trigger a call to the 'write' method of
    the provided object.
    
    Parameters
    ----------
    func : callable f(err, flag) or object with write method
        Function to call upon floating-point errors ('call'-mode) or
        object whose 'write' method is used to log such message ('log'-mode).
    
        The call function takes two arguments. The first is a string describing
        the type of error (such as "divide by zero", "overflow", "underflow",
        or "invalid value"), and the second is the status flag.  The flag is a
        byte, whose four least-significant bits indicate the type of error, one
        of "divide", "over", "under", "invalid"::
    
          [0 0 0 0 divide over under invalid]
    
        In other words, ``flags = divide + 2*over + 4*under + 8*invalid``.
    
        If an object is provided, its write method should take one argument,
        a string.
    
    Returns
    -------
    h : callable, log instance or None
        The old error handler.
    
    See Also
    --------
    seterr, geterr, geterrcall
    
    Examples
    --------
    Callback upon error:
    
    >>> def err_handler(type, flag):
    ...     print("Floating point error (%s), with flag %s" % (type, flag))
    ...
    
    >>> orig_handler = np.seterrcall(err_handler)
    >>> orig_err = np.seterr(all='call')
    
    >>> np.array([1, 2, 3]) / 0.0
    Floating point error (divide by zero), with flag 1
    array([inf, inf, inf])
    
    >>> np.seterrcall(orig_handler)
    <function err_handler at 0x...>
    >>> np.seterr(**orig_err)
    {'divide': 'call', 'over': 'call', 'under': 'call', 'invalid': 'call'}
    
    Log error message:
    
    >>> class Log:
    ...     def write(self, msg):
    ...         print("LOG: %s" % msg)
    ...
    
    >>> log = Log()
    >>> saved_handler = np.seterrcall(log)
    >>> save_err = np.seterr(all='log')
    
    >>> np.array([1, 2, 3]) / 0.0
    LOG: Warning: divide by zero encountered in divide
    array([inf, inf, inf])
    
    >>> np.seterrcall(orig_handler)
    <numpy.Log object at 0x...>
    >>> np.seterr(**orig_err)
    {'divide': 'log', 'over': 'log', 'under': 'log', 'invalid': 'log'}
    
    """
    old = _get_extobj_dict()["call"]
    extobj = _make_extobj(call=func)
    _extobj_contextvar.set(extobj)
    return old
# 设置 numpy 模块的默认模块名为 'numpy'
@set_module('numpy')
# 定义函数 geterrcall,返回当前用于处理浮点错误的回调函数
def geterrcall():
    """
    Return the current callback function used on floating-point errors.

    When the error handling for a floating-point error (one of "divide",
    "over", "under", or "invalid") is set to 'call' or 'log', the function
    that is called or the log instance that is written to is returned by
    `geterrcall`. This function or log instance has been set with
    `seterrcall`.

    Returns
    -------
    errobj : callable, log instance or None
        The current error handler. If no handler was set through `seterrcall`,
        ``None`` is returned.

    See Also
    --------
    seterrcall, seterr, geterr

    Notes
    -----
    For complete documentation of the types of floating-point exceptions and
    treatment options, see `seterr`.

    Examples
    --------
    >>> np.geterrcall()  # we did not yet set a handler, returns None

    >>> orig_settings = np.seterr(all='call')
    >>> def err_handler(type, flag):
    ...     print("Floating point error (%s), with flag %s" % (type, flag))
    >>> old_handler = np.seterrcall(err_handler)
    >>> np.array([1, 2, 3]) / 0.0
    Floating point error (divide by zero), with flag 1
    array([inf, inf, inf])

    >>> cur_handler = np.geterrcall()
    >>> cur_handler is err_handler
    True
    >>> old_settings = np.seterr(**orig_settings)  # restore original
    >>> old_handler = np.seterrcall(None)  # restore original

    """
    return _get_extobj_dict()["call"]


# 定义一个未指定类型的类 _unspecified
class _unspecified:
    pass


# 将 _unspecified 类型的实例赋值给 _Unspecified 变量
_Unspecified = _unspecified()


# 设置 numpy 模块的默认模块名为 'numpy',定义一个类 errstate
@set_module('numpy')
class errstate:
    """
    errstate(**kwargs)

    Context manager for floating-point error handling.

    Using an instance of `errstate` as a context manager allows statements in
    that context to execute with a known error handling behavior. Upon entering
    the context the error handling is set with `seterr` and `seterrcall`, and
    upon exiting it is reset to what it was before.

    ..  versionchanged:: 1.17.0
        `errstate` is also usable as a function decorator, saving
        a level of indentation if an entire function is wrapped.

    .. versionchanged:: 2.0
        `errstate` is now fully thread and asyncio safe, but may not be
        entered more than once.
        It is not safe to decorate async functions using ``errstate``.

    Parameters
    ----------
    kwargs : {divide, over, under, invalid}
        Keyword arguments. The valid keywords are the possible floating-point
        exceptions. Each keyword should have a string value that defines the
        treatment for the particular error. Possible values are
        {'ignore', 'warn', 'raise', 'call', 'print', 'log'}.

    See Also
    --------
    seterr, geterr, seterrcall, geterrcall

    Notes
    -----
    For complete documentation of the types of floating-point exceptions and
    treatment options, see `seterr`.

    Examples
    --------
    >>> olderr = np.seterr(all='ignore')  # Set error handling to known state.


    """
    >>> np.arange(3) / 0.
    array([nan, inf, inf])
    
    
    # 在NumPy中,对一个数组进行除以零操作会产生特定的浮点数错误,结果为NaN和inf。
    >>> with np.errstate(divide='ignore'):
    ...     np.arange(3) / 0.
    array([nan, inf, inf])
    
    
    # 使用`np.errstate`上下文管理器来临时忽略浮点数除以零的错误。
    >>> np.sqrt(-1)
    np.float64(nan)
    
    
    # 调用`np.sqrt`函数对负数求平方根会引发浮点数无效的错误,结果为NaN。
    >>> with np.errstate(invalid='raise'):
    ...     np.sqrt(-1)
    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
    FloatingPointError: invalid value encountered in sqrt
    
    
    # 使用`np.errstate`上下文管理器来设置对浮点数无效操作(如求负数的平方根)抛出异常。
    Outside the context the error handling behavior has not changed:
    >>> np.geterr()
    {'divide': 'ignore', 'over': 'ignore', 'under': 'ignore', 'invalid': 'ignore'}
    
    
    # 在`np.errstate`上下文管理器外,NumPy错误处理状态未发生改变。
    >>> olderr = np.seterr(**olderr)  # restore original state
    
    
    # 使用`np.seterr`恢复先前保存的错误处理状态。
    """
    __slots__ = (
        "_call", "_all", "_divide", "_over", "_under", "_invalid", "_token")
    
    
    # 定义类的`__slots__`属性,限制实例属性的创建,优化内存使用。
    def __init__(self, *, call=_Unspecified,
                 all=None, divide=None, over=None, under=None, invalid=None):
        self._token = None
        self._call = call
        self._all = all
        self._divide = divide
        self._over = over
        self._under = under
        self._invalid = invalid
    
    
    # 初始化`np.errstate`类的实例,设置各种错误处理状态。
    def __enter__(self):
        # Note that __call__ duplicates much of this logic
        if self._token is not None:
            raise TypeError("Cannot enter `np.errstate` twice.")
        if self._call is _Unspecified:
            extobj = _make_extobj(
                    all=self._all, divide=self._divide, over=self._over,
                    under=self._under, invalid=self._invalid)
        else:
            extobj = _make_extobj(
                    call=self._call,
                    all=self._all, divide=self._divide, over=self._over,
                    under=self._under, invalid=self._invalid)
    
        self._token = _extobj_contextvar.set(extobj)
    
    
    # 实现`__enter__`方法,用于进入`np.errstate`上下文管理器,设置错误处理状态。
    def __exit__(self, *exc_info):
        _extobj_contextvar.reset(self._token)
    
    
    # 实现`__exit__`方法,用于退出`np.errstate`上下文管理器,重置错误处理状态。
    def __call__(self, func):
        # We need to customize `__call__` compared to `ContextDecorator`
        # because we must store the token per-thread so cannot store it on
        # the instance (we could create a new instance for this).
        # This duplicates the code from `__enter__`.
        @functools.wraps(func)
        def inner(*args, **kwargs):
            if self._call is _Unspecified:
                extobj = _make_extobj(
                        all=self._all, divide=self._divide, over=self._over,
                        under=self._under, invalid=self._invalid)
            else:
                extobj = _make_extobj(
                        call=self._call,
                        all=self._all, divide=self._divide, over=self._over,
                        under=self._under, invalid=self._invalid)
    
            _token = _extobj_contextvar.set(extobj)
            try:
                # Call the original, decorated, function:
                return func(*args, **kwargs)
            finally:
                _extobj_contextvar.reset(_token)
    
        return inner
    
    
    # 实现`__call__`方法,允许`np.errstate`实例作为装饰器使用,设置错误处理状态。
# 创建一个上下文变量 NO_NEP50_WARNING,用于跟踪是否禁用了 NEP 50 警告
NO_NEP50_WARNING = contextvars.ContextVar("_no_nep50_warning", default=False)

# 将修饰器应用于下面的函数,指定其模块为 'numpy'
@set_module('numpy')
# 定义一个上下文管理器函数 _no_nep50_warning
@contextlib.contextmanager
def _no_nep50_warning():
    """
    上下文管理器,用于禁用 NEP 50 警告。仅在全局启用 NEP 50 警告时才相关
    (这种情况下不是线程/上下文安全)。

    此警告上下文管理器本身是完全安全的。
    """
    # 设置 NO_NEP50_WARNING 上下文变量为 True,并返回一个标记 token
    token = NO_NEP50_WARNING.set(True)
    try:
        # 执行 yield,进入上下文管理器的主体部分
        yield
    finally:
        # 在上下文管理器结束后,重置 NO_NEP50_WARNING 上下文变量为原来的 token
        NO_NEP50_WARNING.reset(token)

.\numpy\numpy\_core\_ufunc_config.pyi

from collections.abc import Callable
from typing import Any, Literal, TypedDict
from numpy import _SupportsWrite

# 定义错误类型的文字字面量类型
_ErrKind = Literal["ignore", "warn", "raise", "call", "print", "log"]

# 定义错误设置字典类型
class _ErrDict(TypedDict):
    divide: _ErrKind    # 错误种类:除法错误
    over: _ErrKind      # 错误种类:溢出错误
    under: _ErrKind     # 错误种类:下溢错误
    invalid: _ErrKind   # 错误种类:无效输入错误

# 定义可选的错误设置字典类型,允许所有错误或特定错误设置为 None
class _ErrDictOptional(TypedDict, total=False):
    all: None | _ErrKind
    divide: None | _ErrKind
    over: None | _ErrKind
    under: None | _ErrKind
    invalid: None | _ErrKind

# 设置错误处理函数的签名及返回类型,返回一个错误设置字典
def seterr(
    all: None | _ErrKind = ...,
    divide: None | _ErrKind = ...,
    over: None | _ErrKind = ...,
    under: None | _ErrKind = ...,
    invalid: None | _ErrKind = ...,
) -> _ErrDict: ...

# 获取当前的错误设置,返回一个错误设置字典
def geterr() -> _ErrDict: ...

# 设置缓冲区大小,返回设置后的大小
def setbufsize(size: int) -> int: ...

# 获取当前缓冲区大小,返回当前设置的大小
def getbufsize() -> int: ...

# 设置错误回调函数的签名及返回类型,可以是 None、函数或支持写操作的对象
def seterrcall(
    func: None | _ErrFunc | _SupportsWrite[str]
) -> None | _ErrFunc | _SupportsWrite[str]: ...

# 获取当前错误回调函数,返回值可以是 None、函数或支持写操作的对象
def geterrcall() -> None | _ErrFunc | _SupportsWrite[str]: ...

# 查阅 `numpy/__init__.pyi` 中的 `errstate` 类和 `no_nep5_warnings` 的相关说明

.\numpy\numpy\_core\__init__.py

"""
Contains the core of NumPy: ndarray, ufuncs, dtypes, etc.

Please note that this module is private.  All functions and objects
are available in the main ``numpy`` namespace - use that instead.

"""

# 导入标准库 os
import os

# 从 numpy.version 模块导入版本号作为 __version__
from numpy.version import version as __version__

# disables OpenBLAS affinity setting of the main thread that limits
# python threads or processes to one core
# 禁用 OpenBLAS 对主线程的亲和性设置,以免限制 Python 线程或进程只能使用一个核心
env_added = []
for envkey in ['OPENBLAS_MAIN_FREE', 'GOTOBLAS_MAIN_FREE']:
    if envkey not in os.environ:
        os.environ[envkey] = '1'
        env_added.append(envkey)

try:
    # 尝试从当前包中导入 multiarray 模块
    from . import multiarray
except ImportError as exc:
    # 如果导入失败,处理 ImportError 异常
    import sys
    msg = """

IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!

Importing the numpy C-extensions failed. This error can happen for
many reasons, often due to issues with your setup or how NumPy was
installed.

We have compiled some common reasons and troubleshooting tips at:

    https://numpy.org/devdocs/user/troubleshooting-importerror.html

Please note and check the following:

  * The Python version is: Python%d.%d from "%s"
  * The NumPy version is: "%s"

and make sure that they are the versions you expect.
Please carefully study the documentation linked above for further help.

Original error was: %s
""" % (sys.version_info[0], sys.version_info[1], sys.executable,
        __version__, exc)
    raise ImportError(msg)
finally:
    # 无论是否发生异常,都要删除添加的环境变量
    for envkey in env_added:
        del os.environ[envkey]
# 删除临时变量和模块
del envkey
del env_added
del os

# 从当前包中导入 umath 模块
from . import umath

# Check that multiarray, umath are pure python modules wrapping
# _multiarray_umath and not either of the old c-extension modules
# 检查 multiarray 和 umath 是否是纯 Python 模块,包装了 _multiarray_umath,而不是旧的 C 扩展模块
if not (hasattr(multiarray, '_multiarray_umath') and
        hasattr(umath, '_multiarray_umath')):
    import sys
    path = sys.modules['numpy'].__path__
    msg = ("Something is wrong with the numpy installation. "
        "While importing we detected an older version of "
        "numpy in {}. One method of fixing this is to repeatedly uninstall "
        "numpy until none is found, then reinstall this version.")
    raise ImportError(msg.format(path))

# 从当前包中导入 numerictypes 模块,并引入其 sctypes 和 sctypeDict
from . import numerictypes as nt
from .numerictypes import sctypes, sctypeDict
# 设置 multiarray 模块的 typeDict 属性为 nt 模块的 sctypeDict
multiarray.set_typeDict(nt.sctypeDict)
# 从当前包中导入 numeric 模块的所有内容
from . import numeric
from .numeric import *
# 从当前包中导入 fromnumeric 模块的所有内容
from . import fromnumeric
from .fromnumeric import *
# 从当前包中导入 records 模块的 record 和 recarray 类
from .records import record, recarray
# Note: module name memmap is overwritten by a class with same name
# 从 memmap 模块导入所有内容(注意:模块名 memmap 被同名类覆盖)
from .memmap import *
# 从当前包中导入 function_base 模块的所有内容
from . import function_base
from .function_base import *
# 从当前包中导入 _machar 模块
from . import _machar
# 从当前包中导入 getlimits 模块的所有内容
from . import getlimits
from .getlimits import *
# 从当前包中导入 shape_base 模块的所有内容
from . import shape_base
from .shape_base import *
# 从当前包中导入 einsumfunc 模块的所有内容
from . import einsumfunc
from .einsumfunc import *
# 删除 nt 变量,清理命名空间
del nt

# 从 numeric 模块中导入 absolute 函数并命名为 abs
from .numeric import absolute as abs

# do this after everything else, to minimize the chance of this misleadingly
# appearing in an import-time traceback
# 从当前包中导入 _add_newdocs 模块
from . import _add_newdocs
# 从当前包中导入 _add_newdocs_scalars 模块
from . import _add_newdocs_scalars
# add these for module-freeze analysis (like PyInstaller)
# 从当前包中导入 _dtype_ctypes 模块
from . import _dtype_ctypes
# 从当前包中导入 _internal 模块
from . import _internal
from . import _dtype
from . import _methods


# 导入模块 _dtype 和 _methods,它们位于当前包中的子模块



acos = numeric.arccos
acosh = numeric.arccosh
asin = numeric.arcsin
asinh = numeric.arcsinh
atan = numeric.arctan
atanh = numeric.arctanh
atan2 = numeric.arctan2
concat = numeric.concatenate
bitwise_left_shift = numeric.left_shift
bitwise_invert = numeric.invert
bitwise_right_shift = numeric.right_shift
permute_dims = numeric.transpose
pow = numeric.power


# 给一些函数和方法赋值,以便后续使用,这些函数和方法来自 numeric 模块
# numeric 是一个导入的模块,这些函数和方法在后续代码中可能会被使用



__all__ = [
    "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2",
    "bitwise_invert", "bitwise_left_shift", "bitwise_right_shift", "concat",
    "pow", "permute_dims", "memmap", "sctypeDict", "record", "recarray"
]
__all__ += numeric.__all__
__all__ += function_base.__all__
__all__ += getlimits.__all__
__all__ += shape_base.__all__
__all__ += einsumfunc.__all__


# 定义 __all__ 列表,包含导出的模块、函数和方法名称
# 这些名称被视为模块的公共 API,可以通过 `from module import *` 导入
# 还包括其他模块的公共 API,如 numeric、function_base、getlimits、shape_base 和 einsumfunc



def _ufunc_reduce(func):
    # 返回函数的 __name__ 属性,用于在 pickle 模块中找到相应的模块
    # pickle 模块支持使用 `__qualname__` 来查找模块,这对于明确指定 ufuncs(通用函数)很有用
    # 参考:https://github.com/dask/distributed/issues/3450
    return func.__name__


def _DType_reconstruct(scalar_type):
    # 这是 pickle np.dtype(np.float64) 等类型的一个解决方法
    # 应该用更好的解决方法替代,比如当 DTypes 变为 HeapTypes 时
    return type(dtype(scalar_type))


def _DType_reduce(DType):
    # 大多数 DTypes 可以简单地通过它们的名称来 pickle
    if not DType._legacy or DType.__module__ == "numpy.dtypes":
        return DType.__name__

    # 对于用户定义的 legacy DTypes(如 rational),它们不在 numpy.dtypes 中并且没有公共类
    # 对于这些情况,我们通过从标量类型重建它们来 pickle 它们
    scalar_type = DType.type
    return _DType_reconstruct, (scalar_type,)


# 定义了两个辅助函数,用于 pickle 特定类型的对象
# _ufunc_reduce 用于通用函数的 pickle
# _DType_reduce 和 _DType_reconstruct 用于数据类型对象的 pickle



def __getattr__(name):
    # Deprecated 2022-11-22, NumPy 1.25.
    if name == "MachAr":
        import warnings
        warnings.warn(
            "The `np._core.MachAr` is considered private API (NumPy 1.24)",
            DeprecationWarning, stacklevel=2,
        )
        return _machar.MachAr
    raise AttributeError(f"Module {__name__!r} has no attribute {name!r}")


# __getattr__ 方法用于动态获取模块的属性
# 如果请求的属性名是 "MachAr",则发出警告,并返回 _machar.MachAr
# 否则,引发 AttributeError 异常,指示模块没有该属性
# 注意:该方法已于 NumPy 1.25 弃用于 2022-11-22



import copyreg

copyreg.pickle(ufunc, _ufunc_reduce)
copyreg.pickle(type(dtype), _DType_reduce, _DType_reconstruct)

# Unclutter namespace (must keep _*_reconstruct for unpickling)
del copyreg, _ufunc_reduce, _DType_reduce


# 使用 copyreg.pickle 方法注册用于序列化的函数
# ufunc 对象使用 _ufunc_reduce 函数进行 pickle
# dtype 类型使用 _DType_reduce 和 _DType_reconstruct 进行 pickle
# 删除 copyreg、_ufunc_reduce 和 _DType_reduce 变量,以清理命名空间



from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
del PytestTester


# 导入 PytestTester 类,并将当前模块的名称传递给它来进行测试
# 将 PytestTester 实例赋值给 test 变量
# 删除 PytestTester 类,以清理命名空间

.\numpy\numpy\_core\__init__.pyi

# NOTE: `np._core` 命名空间被故意保持为空,因为它是私有的

.\numpy\numpy\_distributor_init.py

"""
Distributor init file

Distributors: you can add custom code here to support particular distributions
of numpy.

For example, this is a good place to put any BLAS/LAPACK initialization code.

The numpy standard source distribution will not put code in this file, so you
can safely replace this file with your own version.
"""

# 尝试导入本地的 _distributor_init_local 模块
try:
    from . import _distributor_init_local
# 如果导入失败,则忽略该错误继续执行
except ImportError:
    pass

.\numpy\numpy\_expired_attrs_2_0.py

"""
Dict of expired attributes that are discontinued since 2.0 release.
Each item is associated with a migration note.
"""

# 这是一个包含自2.0版本以来已停用属性的字典。
# 每个条目都附带有迁移说明。

__expired_attributes__ = {
    "geterrobj": "Use the np.errstate context manager instead.",
    # 使用 np.errstate 上下文管理器替代。
    "seterrobj": "Use the np.errstate context manager instead.",
    # 使用 np.errstate 上下文管理器替代。
    "cast": "Use `np.asarray(arr, dtype=dtype)` instead.",
    # 使用 `np.asarray(arr, dtype=dtype)` 替代。
    "source": "Use `inspect.getsource` instead.",
    # 使用 `inspect.getsource` 替代。
    "lookfor":  "Search NumPy's documentation directly.",
    # 直接搜索 NumPy 文档。
    "who": "Use an IDE variable explorer or `locals()` instead.",
    # 使用 IDE 的变量资源管理器或 `locals()` 替代。
    "fastCopyAndTranspose": "Use `arr.T.copy()` instead.",
    # 使用 `arr.T.copy()` 替代。
    "set_numeric_ops": 
        "For the general case, use `PyUFunc_ReplaceLoopBySignature`. "
        "For ndarray subclasses, define the ``__array_ufunc__`` method "
        "and override the relevant ufunc.",
    # 对于一般情况,请使用 `PyUFunc_ReplaceLoopBySignature`。
    # 对于 ndarray 子类,请定义 `__array_ufunc__` 方法并重写相关的 ufunc。
    "NINF": "Use `-np.inf` instead.",
    # 使用 `-np.inf` 替代。
    "PINF": "Use `np.inf` instead.",
    # 使用 `np.inf` 替代。
    "NZERO": "Use `-0.0` instead.",
    # 使用 `-0.0` 替代。
    "PZERO": "Use `0.0` instead.",
    # 使用 `0.0` 替代。
    "add_newdoc": 
        "It's still available as `np.lib.add_newdoc`.",
    # 仍然可以使用 `np.lib.add_newdoc`。
    "add_docstring": 
        "It's still available as `np.lib.add_docstring`.",
    # 仍然可以使用 `np.lib.add_docstring`。
    "add_newdoc_ufunc": 
        "It's an internal function and doesn't have a replacement.",
    # 这是一个内部函数,没有替代方法。
    "compat": "There's no replacement, as Python 2 is no longer supported.",
    # 没有替代方法,因为不再支持 Python 2。
    "safe_eval": "Use `ast.literal_eval` instead.",
    # 使用 `ast.literal_eval` 替代。
    "float_": "Use `np.float64` instead.",
    # 使用 `np.float64` 替代。
    "complex_": "Use `np.complex128` instead.",
    # 使用 `np.complex128` 替代。
    "longfloat": "Use `np.longdouble` instead.",
    # 使用 `np.longdouble` 替代。
    "singlecomplex": "Use `np.complex64` instead.",
    # 使用 `np.complex64` 替代。
    "cfloat": "Use `np.complex128` instead.",
    # 使用 `np.complex128` 替代。
    "longcomplex": "Use `np.clongdouble` instead.",
    # 使用 `np.clongdouble` 替代。
    "clongfloat": "Use `np.clongdouble` instead.",
    # 使用 `np.clongdouble` 替代。
    "string_": "Use `np.bytes_` instead.",
    # 使用 `np.bytes_` 替代。
    "unicode_": "Use `np.str_` instead.",
    # 使用 `np.str_` 替代。
    "Inf": "Use `np.inf` instead.",
    # 使用 `np.inf` 替代。
    "Infinity": "Use `np.inf` instead.",
    # 使用 `np.inf` 替代。
    "NaN": "Use `np.nan` instead.",
    # 使用 `np.nan` 替代。
    "infty": "Use `np.inf` instead.",
    # 使用 `np.inf` 替代。
    "issctype": "Use `issubclass(rep, np.generic)` instead.",
    # 使用 `issubclass(rep, np.generic)` 替代。
    "maximum_sctype":
        "Use a specific dtype instead. You should avoid relying "
        "on any implicit mechanism and select the largest dtype of "
        "a kind explicitly in the code.",
    # 使用特定的 dtype 替代。应避免依赖任何隐式机制,并在代码中明确选择一种 dtype 的最大值。
    "obj2sctype": "Use `np.dtype(obj).type` instead.",
    # 使用 `np.dtype(obj).type` 替代。
    "sctype2char": "Use `np.dtype(obj).char` instead.",
    # 使用 `np.dtype(obj).char` 替代。
    "sctypes": "Access dtypes explicitly instead.",
    # 直接访问 dtypes。
    "issubsctype": "Use `np.issubdtype` instead.",
    # 使用 `np.issubdtype` 替代。
    "set_string_function": 
        "Use `np.set_printoptions` instead with a formatter for "
        "custom printing of NumPy objects.",
    # 使用 `np.set_printoptions` 并为自定义打印 NumPy 对象设置格式化器。
    "asfarray": "Use `np.asarray` with a proper dtype instead.",
    # 使用带有正确 dtype 的 `np.asarray` 替代。
    "issubclass_": "Use `issubclass` builtin instead.",
    # 使用内置的 `issubclass` 替代。
    "tracemalloc_domain": "It's now available from `np.lib`.",
    # 现在可以从 `np.lib` 获取。
    "mat": "Use `np.asmatrix` instead.",
    # 使用 `np.asmatrix` 替代。
    "recfromcsv": "Use `np.genfromtxt` with comma delimiter instead.",
    # 使用带有逗号分隔符的 `np.genfromtxt` 替代。
    "recfromtxt": "Use `np.genfromtxt` instead.",
    # 使用 `np.genfromtxt` 替代。
    "deprecate": "Emit `DeprecationWarning` with `warnings.warn` directly, "
        "or use `typing.deprecated`.",
    # 直接发出 `DeprecationWarning`,或者使用 `warnings.warn`。
    "deprecate_with_doc": "Emit `DeprecationWarning` with `warnings.warn` "
        "directly, or use `typing.deprecated`.",
    # 建议使用 `warnings.warn` 直接发出 `DeprecationWarning`,或者使用 `typing.deprecated`。
    "disp": "Use your own printing function instead.",
    # 建议使用自己的打印函数代替。
    "find_common_type": 
        "Use `numpy.promote_types` or `numpy.result_type` instead. "
        "To achieve semantics for the `scalar_types` argument, use "
        "`numpy.result_type` and pass the Python values `0`, `0.0`, or `0j`.",
    # 建议使用 `numpy.promote_types` 或 `numpy.result_type`。为了实现 `scalar_types` 参数的语义,可以使用 `numpy.result_type` 并传递 Python 值 `0`、`0.0` 或 `0j`。
    "round_": "Use `np.round` instead.",
    # 建议使用 `np.round` 替代。
    "get_array_wrap": "",
    # 无注释内容,可能表示此处无特别需要说明的内容。
    "DataSource": "It's still available as `np.lib.npyio.DataSource`.", 
    # 仍可通过 `np.lib.npyio.DataSource` 获取此功能。
    "nbytes": "Use `np.dtype(<dtype>).itemsize` instead.",  
    # 建议使用 `np.dtype(<dtype>).itemsize` 替代。
    "byte_bounds": "Now it's available under `np.lib.array_utils.byte_bounds`",
    # 现在可以在 `np.lib.array_utils.byte_bounds` 下找到此功能。
    "compare_chararrays": 
        "It's still available as `np.char.compare_chararrays`.",
    # 仍可通过 `np.char.compare_chararrays` 获取此功能。
    "format_parser": "It's still available as `np.rec.format_parser`."
    # 仍可通过 `np.rec.format_parser` 获取此功能。
}


注释:

# 这是一个单独的右大括号,用于结束一个代码块或语句。

.\numpy\numpy\_globals.py

"""
Module defining global singleton classes.

This module raises a RuntimeError if an attempt to reload it is made. In that
way the identities of the classes defined here are fixed and will remain so
even if numpy itself is reloaded. In particular, a function like the following
will still work correctly after numpy is reloaded::

    def foo(arg=np._NoValue):
        if arg is np._NoValue:
            ...

That was not the case when the singleton classes were defined in the numpy
``__init__.py`` file. See gh-7844 for a discussion of the reload problem that
motivated this module.

"""
import enum

from ._utils import set_module as _set_module

__all__ = ['_NoValue', '_CopyMode']


# Disallow reloading this module so as to preserve the identities of the
# classes defined here.
if '_is_loaded' in globals():
    # 如果已经加载过,则阻止重新加载,确保类在此处定义的身份不变
    raise RuntimeError('Reloading numpy._globals is not allowed')
_is_loaded = True


class _NoValueType:
    """Special keyword value.

    The instance of this class may be used as the default value assigned to a
    keyword if no other obvious default (e.g., `None`) is suitable,

    Common reasons for using this keyword are:

    - A new keyword is added to a function, and that function forwards its
      inputs to another function or method which can be defined outside of
      NumPy. For example, ``np.std(x)`` calls ``x.std``, so when a ``keepdims``
      keyword was added that could only be forwarded if the user explicitly
      specified ``keepdims``; downstream array libraries may not have added
      the same keyword, so adding ``x.std(..., keepdims=keepdims)``
      unconditionally could have broken previously working code.
    - A keyword is being deprecated, and a deprecation warning must only be
      emitted when the keyword is used.

    """
    __instance = None
    def __new__(cls):
        # ensure that only one instance exists
        if not cls.__instance:
            cls.__instance = super().__new__(cls)
        return cls.__instance

    def __repr__(self):
        return "<no value>"


_NoValue = _NoValueType()  # 创建 _NoValue 的单例实例


@_set_module("numpy")
class _CopyMode(enum.Enum):
    """
    An enumeration for the copy modes supported
    by numpy.copy() and numpy.array(). The following three modes are supported,

    - ALWAYS: This means that a deep copy of the input
              array will always be taken.
    - IF_NEEDED: This means that a deep copy of the input
                 array will be taken only if necessary.
    - NEVER: This means that the deep copy will never be taken.
             If a copy cannot be avoided then a `ValueError` will be
             raised.

    Note that the buffer-protocol could in theory do copies.  NumPy currently
    assumes an object exporting the buffer protocol will never do this.
    """

    ALWAYS = True  # 深拷贝,总是复制数组
    NEVER = False  # 永不拷贝,如果无法避免则引发 ValueError
    IF_NEEDED = 2  # 根据需要拷贝,仅在必要时才复制
    # 定义一个特殊方法 __bool__,用于确定对象的布尔值
    def __bool__(self):
        # 检查对象是否等于 _CopyMode.ALWAYS,如果是,则返回 True
        if self == _CopyMode.ALWAYS:
            return True
        
        # 检查对象是否等于 _CopyMode.NEVER,如果是,则返回 False
        if self == _CopyMode.NEVER:
            return False
        
        # 如果对象既不等于 _CopyMode.ALWAYS 也不等于 _CopyMode.NEVER,则抛出 ValueError 异常
        raise ValueError(f"{self} is neither True nor False.")

.\numpy\numpy\_pyinstaller\hook-numpy.py

# 导入必要的模块和函数
"""This hook should collect all binary files and any hidden modules that numpy
needs.

Our (some-what inadequate) docs for writing PyInstaller hooks are kept here:
https://pyinstaller.readthedocs.io/en/stable/hooks.html

"""
from PyInstaller.compat import is_conda, is_pure_conda  # 导入 PyInstaller 兼容性模块中的 is_conda 和 is_pure_conda 函数
from PyInstaller.utils.hooks import collect_dynamic_libs, is_module_satisfies  # 导入 PyInstaller 工具模块中的 collect_dynamic_libs 和 is_module_satisfies 函数

# 收集 numpy 安装文件夹中所有的 DLL 文件,并将它们放置在构建后的应用程序根目录
binaries = collect_dynamic_libs("numpy", ".")

# 如果使用 Conda 而没有任何非 Conda 虚拟环境管理器:
if is_pure_conda:
    # 假定从 Conda-forge 运行 NumPy,并从共享的 Conda bin 目录收集其 DLL 文件。必须同时收集 NumPy 依赖项的 DLL 文件,以捕获 MKL、OpenBlas、OpenMP 等。
    from PyInstaller.utils.hooks import conda_support
    datas = conda_support.collect_dynamic_libs("numpy", dependencies=True)

# PyInstaller 无法检测到的子模块。'_dtype_ctypes' 仅从 C 语言中导入,'_multiarray_tests' 用于测试(不会被打包)。
hiddenimports = ['numpy._core._dtype_ctypes', 'numpy._core._multiarray_tests']

# 移除 NumPy 中引用但实际上并非依赖的测试和构建代码及包。
excludedimports = [
    "scipy",
    "pytest",
    "f2py",
    "setuptools",
    "numpy.f2py",
    "distutils",
    "numpy.distutils",
]

.\numpy\numpy\_pyinstaller\tests\pyinstaller-smoke.py

"""A crude *bit of everything* smoke test to verify PyInstaller compatibility.

PyInstaller typically goes wrong by forgetting to package modules, extension
modules or shared libraries. This script should aim to touch as many of those
as possible in an attempt to trip a ModuleNotFoundError or a DLL load failure
due to an uncollected resource. Missing resources are unlikely to lead to
arithmetic errors so there's generally no need to verify any calculation's
output - merely that it made it to the end OK. This script should not
explicitly import any of numpy's submodules as that gives PyInstaller undue
hints that those submodules exist and should be collected (accessing implicitly
loaded submodules is OK).

"""

# 导入 numpy 库,进行各种数值计算和线性代数操作的测试
import numpy as np

# 创建一个 3x3 的数组并对 5 取模
a = np.arange(1., 10.).reshape((3, 3)) % 5

# 计算数组 a 的行列式
np.linalg.det(a)

# 计算数组 a 与自身的矩阵乘积
a @ a

# 计算数组 a 与其转置的矩阵乘积
a @ a.T

# 计算数组 a 的逆矩阵
np.linalg.inv(a)

# 对数组 a 中的每个元素先计算指数,再求正弦
np.sin(np.exp(a))

# 对数组 a 进行奇异值分解
np.linalg.svd(a)

# 对数组 a 进行特征值分解
np.linalg.eigh(a)

# 生成一个包含 0 到 9 之间随机整数的数组,并返回其中的唯一值
np.unique(np.random.randint(0, 10, 100))

# 生成一个包含 0 到 10 之间均匀分布的随机数的数组,并对其进行排序
np.sort(np.random.uniform(0, 10, 100))

# 对一个复数数组进行傅里叶变换
np.fft.fft(np.exp(2j * np.pi * np.arange(8) / 8))

# 创建一个掩码数组,并计算其中被掩盖的部分的和
np.ma.masked_array(np.arange(10), np.random.rand(10) < .5).sum()

# 计算 Legendre 多项式的根
np.polynomial.Legendre([7, 8, 9]).roots()

# 输出测试通过的消息
print("I made it!")

.\numpy\numpy\_pyinstaller\tests\test_pyinstaller.py

# 导入必要的模块
import subprocess  # 子进程管理模块,用于执行外部命令
from pathlib import Path  # 提供处理文件和目录路径的类和函数

import pytest  # 测试框架 pytest


# 忽略 PyInstaller 中关于 'imp' 替换为 'importlib' 的警告
@pytest.mark.filterwarnings('ignore::DeprecationWarning')
# 忽略关于 io.BytesIO() 泄漏的资源警告
@pytest.mark.filterwarnings('ignore::ResourceWarning')
# 参数化测试,分别测试 '--onedir' 和 '--onefile' 两种模式
@pytest.mark.parametrize("mode", ["--onedir", "--onefile"])
@pytest.mark.slow  # 标记为慢速测试,可能需要较长时间运行
def test_pyinstaller(mode, tmp_path):
    """Compile and run pyinstaller-smoke.py using PyInstaller."""

    # 导入并运行 PyInstaller 主程序
    pyinstaller_cli = pytest.importorskip("PyInstaller.__main__").run

    # 获取要编译的源文件的路径,并确保其为绝对路径
    source = Path(__file__).with_name("pyinstaller-smoke.py").resolve()

    # 构造 PyInstaller 的命令行参数列表
    args = [
        # 将所有生成的文件放置在 tmp_path 指定的路径中
        '--workpath', str(tmp_path / "build"),
        '--distpath', str(tmp_path / "dist"),
        '--specpath', str(tmp_path),
        mode,  # 使用当前参数化的模式
        str(source),  # 源文件的绝对路径
    ]

    # 调用 PyInstaller 主程序并传入参数执行编译
    pyinstaller_cli(args)

    # 根据模式选择生成的可执行文件路径
    if mode == "--onefile":
        exe = tmp_path / "dist" / source.stem
    else:
        exe = tmp_path / "dist" / source.stem / source.stem

    # 运行生成的可执行文件,并获取其输出结果
    p = subprocess.run([str(exe)], check=True, stdout=subprocess.PIPE)
    # 断言输出结果是否为预期的 "I made it!"
    assert p.stdout.strip() == b"I made it!"

.\numpy\numpy\_pyinstaller\tests\__init__.py

# 从 numpy.testing 模块导入 IS_WASM 和 IS_EDITABLE 常量
from numpy.testing import IS_WASM, IS_EDITABLE
# 导入 pytest 模块,用于测试框架

# 如果 IS_WASM 常量为真,跳过当前测试并显示相应信息
if IS_WASM:
    pytest.skip(
        "WASM/Pyodide does not use or support Fortran",
        allow_module_level=True
    )

# 如果 IS_EDITABLE 常量为真,跳过当前测试并显示相应信息
if IS_EDITABLE:
    pytest.skip(
        "Editable install doesn't support tests with a compile step",
        allow_module_level=True
    )

.\numpy\numpy\_pyinstaller\__init__.py

# 导入所需的模块:datetime 和 timedelta
from datetime import datetime, timedelta

# 定义一个函数,计算指定日期加上指定天数后的日期,并返回结果
def add_days(date_str, days):
    # 将日期字符串转换为 datetime 对象
    date = datetime.strptime(date_str, '%Y-%m-%d')
    # 创建一个 timedelta 对象,表示要增加的天数
    delta = timedelta(days=days)
    # 使用 timedelta 对象增加日期
    new_date = date + delta
    # 将计算后的日期对象格式化为字符串,返回结果
    return new_date.strftime('%Y-%m-%d')

.\numpy\numpy\_pytesttester.py

"""
Pytest test running.

This module implements the ``test()`` function for NumPy modules. The usual
boiler plate for doing that is to put the following in the module
``__init__.py`` file::

    from numpy._pytesttester import PytestTester
    test = PytestTester(__name__)
    del PytestTester


Warnings filtering and other runtime settings should be dealt with in the
``pytest.ini`` file in the numpy repo root. The behavior of the test depends on
whether or not that file is found as follows:

* ``pytest.ini`` is present (develop mode)
    All warnings except those explicitly filtered out are raised as error.
* ``pytest.ini`` is absent (release mode)
    DeprecationWarnings and PendingDeprecationWarnings are ignored, other
    warnings are passed through.

In practice, tests run from the numpy repo are run in development mode with
``spin``, through the standard ``spin test`` invocation or from an inplace
build with ``pytest numpy``.

This module is imported by every numpy subpackage, so lies at the top level to
simplify circular import issues. For the same reason, it contains no numpy
imports at module scope, instead importing numpy within function calls.
"""
import sys
import os

__all__ = ['PytestTester']


class PytestTester:
    """
    Pytest test runner.

    A test function is typically added to a package's __init__.py like so::

      from numpy._pytesttester import PytestTester
      test = PytestTester(__name__).test
      del PytestTester

    Calling this test function finds and runs all tests associated with the
    module and all its sub-modules.

    Attributes
    ----------
    module_name : str
        Full path to the package to test.

    Parameters
    ----------
    module_name : module name
        The name of the module to test.

    Notes
    -----
    Unlike the previous ``nose``-based implementation, this class is not
    publicly exposed as it performs some ``numpy``-specific warning
    suppression.

    """
    # 初始化方法,接收模块名作为参数
    def __init__(self, module_name):
        self.module_name = module_name

.\numpy\numpy\_pytesttester.pyi

from collections.abc import Iterable
from typing import Literal as L

# 定义一个列表,用于指定模块的公开接口
__all__: list[str]

# 定义一个名为 PytestTester 的类
class PytestTester:
    # 类属性,存储模块名
    module_name: str

    # 类的初始化方法,接受一个模块名参数
    def __init__(self, module_name: str) -> None: ...

    # 类的调用方法,用于执行测试
    def __call__(
        self,
        label: L["fast", "full"] = ...,
        verbose: int = ...,
        extra_argv: None | Iterable[str] = ...,
        doctests: L[False] = ...,
        coverage: bool = ...,
        durations: int = ...,
        tests: None | Iterable[str] = ...,
    ) -> bool: ...

.\numpy\numpy\_typing\_add_docstring.py

"""A module for creating docstrings for sphinx ``data`` domains."""

# 导入正则表达式和文本包装模块
import re
import textwrap

# 导入 NDArray 类型
from ._array_like import NDArray

# 全局变量,用于存储文档字符串的列表
_docstrings_list = []


def add_newdoc(name: str, value: str, doc: str) -> None:
    """Append ``_docstrings_list`` with a docstring for `name`.

    Parameters
    ----------
    name : str
        The name of the object.
    value : str
        A string-representation of the object.
    doc : str
        The docstring of the object.

    """
    # 将 name, value, doc 组成的元组添加到 _docstrings_list 中
    _docstrings_list.append((name, value, doc))


def _parse_docstrings() -> str:
    """Convert all docstrings in ``_docstrings_list`` into a single
    sphinx-legible text block.

    """
    # 初始化空列表,用于存储转换后的文本块
    type_list_ret = []
    
    # 遍历 _docstrings_list 中的每个元组 (name, value, doc)
    for name, value, doc in _docstrings_list:
        # 根据 docstring 的缩进,去除缩进并替换换行符
        s = textwrap.dedent(doc).replace("\n", "\n    ")

        # 将文本按行分割
        lines = s.split("\n")
        new_lines = []
        indent = ""

        # 遍历每一行文本
        for line in lines:
            # 使用正则表达式匹配 Rubric 或 Admonition 标记的文本行
            m = re.match(r'^(\s+)[-=]+\s*$', line)
            if m and new_lines:
                # 如果匹配成功且存在前一行,则进行相应的转换
                prev = textwrap.dedent(new_lines.pop())
                if prev == "Examples":
                    indent = ""
                    new_lines.append(f'{m.group(1)}.. rubric:: {prev}')
                else:
                    indent = 4 * " "
                    new_lines.append(f'{m.group(1)}.. admonition:: {prev}')
                new_lines.append("")
            else:
                new_lines.append(f"{indent}{line}")

        # 重新组合处理后的行文本
        s = "\n".join(new_lines)

        # 构建最终的 Sphinx 数据域文本块
        s_block = f""".. data:: {name}\n    :value: {value}\n    {s}"""
        type_list_ret.append(s_block)
    
    # 返回所有文本块组成的单个字符串
    return "\n".join(type_list_ret)


# 示例添加两个文档字符串到 _docstrings_list 中
add_newdoc('ArrayLike', 'typing.Union[...]',
    """
    A `~typing.Union` representing objects that can be coerced
    into an `~numpy.ndarray`.

    Among others this includes the likes of:

    * Scalars.
    * (Nested) sequences.
    * Objects implementing the `~class.__array__` protocol.

    .. versionadded:: 1.20

    See Also
    --------
    :term:`array_like`:
        Any scalar or sequence that can be interpreted as an ndarray.

    Examples
    --------
    .. code-block:: python

        >>> import numpy as np
        >>> import numpy.typing as npt

        >>> def as_array(a: npt.ArrayLike) -> np.ndarray:
        ...     return np.array(a)

    """)

add_newdoc('DTypeLike', 'typing.Union[...]',
    """
    A `~typing.Union` representing objects that can be coerced
    into a `~numpy.dtype`.

    Among others this includes the likes of:

    * :class:`type` objects.
    * Character codes or the names of :class:`type` objects.
    * Objects with the ``.dtype`` attribute.

    .. versionadded:: 1.20

    See Also
    --------
    :ref:`Specifying and constructing data types <arrays.dtypes.constructing>`
        A comprehensive overview of all objects that can be coerced
        into data types.

    Examples
    --------

    """
    # 导入 NumPy 库和 NumPy 的类型提示模块
    import numpy as np
    import numpy.typing as npt
    
    # 定义一个函数 `as_dtype`,用于将输入参数 `d` 转换为 NumPy 的数据类型 (`np.dtype`)
    def as_dtype(d: npt.DTypeLike) -> np.dtype:
        # 返回参数 `d` 对应的 NumPy 数据类型对象 (`np.dtype`)
        return np.dtype(d)
add_newdoc('NDArray', repr(NDArray),
    """
    定义一个 `np.ndarray[Any, np.dtype[+ScalarType]] <numpy.ndarray>` 类型的别名,
    其中 `dtype.type <numpy.dtype.type>` 是关于泛型类型的概念。

    可以在运行时用于定义具有给定 dtype 和未指定形状的数组。

    .. versionadded:: 1.21

    示例
    --------
    .. code-block:: python

        >>> import numpy as np
        >>> import numpy.typing as npt

        >>> print(npt.NDArray)
        numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]

        >>> print(npt.NDArray[np.float64])
        numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]

        >>> NDArrayInt = npt.NDArray[np.int_]
        >>> a: NDArrayInt = np.arange(10)

        >>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
        ...     return np.array(a)

    """
)

_docstrings = _parse_docstrings()

.\numpy\numpy\_typing\_array_like.py

from __future__ import annotations
# 导入未来版本兼容性的模块

import sys
# 导入系统相关的模块
from collections.abc import Collection, Callable, Sequence
# 导入集合、可调用对象和序列相关的抽象基类
from typing import Any, Protocol, Union, TypeVar, runtime_checkable
# 导入类型提示相关的模块

import numpy as np
# 导入NumPy库并使用别名np
from numpy import (
    ndarray,
    dtype,
    generic,
    unsignedinteger,
    integer,
    floating,
    complexfloating,
    number,
    timedelta64,
    datetime64,
    object_,
    void,
    str_,
    bytes_,
)
# 从NumPy库中导入多个特定的类和函数

from ._nested_sequence import _NestedSequence
# 从嵌套序列模块导入_NestedSequence类

_T = TypeVar("_T")
# 创建类型变量_T
_ScalarType = TypeVar("_ScalarType", bound=generic)
# 创建类型变量_ScalarType,限定为泛型类型
_ScalarType_co = TypeVar("_ScalarType_co", bound=generic, covariant=True)
# 创建协变的泛型类型变量_ScalarType_co
_DType = TypeVar("_DType", bound=dtype[Any])
# 创建类型变量_DType,限定为dtype类型
_DType_co = TypeVar("_DType_co", covariant=True, bound=dtype[Any])
# 创建协变的类型变量_DType_co

NDArray = ndarray[Any, dtype[_ScalarType_co]]
# 创建NDArray类型别名,表示任意形状的NumPy数组

# The `_SupportsArray` protocol only cares about the default dtype
# (i.e. `dtype=None` or no `dtype` parameter at all) of the to-be returned
# array.
# Concrete implementations of the protocol are responsible for adding
# any and all remaining overloads
@runtime_checkable
class _SupportsArray(Protocol[_DType_co]):
    def __array__(self) -> ndarray[Any, _DType_co]: ...
# 创建SupportsArray协议类,用于支持数组操作,协变于dtype类型_DType_co

@runtime_checkable
class _SupportsArrayFunc(Protocol):
    """A protocol class representing `~class.__array_function__`."""
    def __array_function__(
        self,
        func: Callable[..., Any],
        types: Collection[type[Any]],
        args: tuple[Any, ...],
        kwargs: dict[str, Any],
    ) -> object: ...
# 创建SupportsArrayFunc协议类,用于支持__array_function__方法的协议定义

# TODO: Wait until mypy supports recursive objects in combination with typevars
_FiniteNestedSequence = Union[
    _T,
    Sequence[_T],
    Sequence[Sequence[_T]],
    Sequence[Sequence[Sequence[_T]]],
    Sequence[Sequence[Sequence[Sequence[_T]]]],
]
# 创建有限的嵌套序列类型别名,支持多级嵌套的序列类型

# A subset of `npt.ArrayLike` that can be parametrized w.r.t. `np.generic`
_ArrayLike = Union[
    _SupportsArray[dtype[_ScalarType]],
    _NestedSequence[_SupportsArray[dtype[_ScalarType]]],
]
# 创建ArrayLike类型别名,表示可以参数化为np.generic类型的npt.ArrayLike子集

# A union representing array-like objects; consists of two typevars:
# One representing types that can be parametrized w.r.t. `np.dtype`
# and another one for the rest
_DualArrayLike = Union[
    _SupportsArray[_DType],
    _NestedSequence[_SupportsArray[_DType]],
    _T,
    _NestedSequence[_T],
]
# 创建DualArrayLike类型别名,表示数组样式对象的联合类型,包含可参数化为np.dtype的类型和其他类型

if sys.version_info >= (3, 12):
    from collections.abc import Buffer
    # 如果Python版本高于等于3.12,则导入Buffer抽象基类

    ArrayLike = Buffer | _DualArrayLike[
        dtype[Any],
        Union[bool, int, float, complex, str, bytes],
    ]
else:
    ArrayLike = _DualArrayLike[
        dtype[Any],
        Union[bool, int, float, complex, str, bytes],
    ]
# 根据Python版本选择性定义ArrayLike类型别名,支持缓冲区或其他类型

# `ArrayLike<X>_co`: array-like objects that can be coerced into `X`
# given the casting rules `same_kind`
_ArrayLikeBool_co = _DualArrayLike[
    dtype[np.bool],
    bool,
]
# 创建ArrayLikeBool_co类型别名,表示可以强制转换为布尔类型的数组样式对象

_ArrayLikeUInt_co = _DualArrayLike[
    dtype[Union[np.bool, unsignedinteger[Any]]],
    bool,
]
# 创建ArrayLikeUInt_co类型别名,表示可以强制转换为无符号整数类型的数组样式对象

_ArrayLikeInt_co = _DualArrayLike[
    dtype[Union[np.bool, integer[Any]]],
    Union[bool, int],
]
# 创建ArrayLikeInt_co类型别名,表示可以强制转换为整数类型的数组样式对象

_ArrayLikeFloat_co = _DualArrayLike[
    dtype[Union[np.bool, integer[Any], floating[Any]]],
    Union[bool, int, float],


# 定义一个类型注解,表示此处的变量或参数可以是 bool、int 或 float 类型之一
# 定义一个类型别名 _ArrayLikeComplex_co,表示复杂类型数组,可以包含布尔值、任意整数、任意浮点数、任意复数
_ArrayLikeComplex_co = _DualArrayLike[
    dtype[Union[
        np.bool,
        integer[Any],
        floating[Any],
        complexfloating[Any, Any],
    ]],
    Union[bool, int, float, complex],
]

# 定义一个类型别名 _ArrayLikeNumber_co,表示数字类型数组,可以包含布尔值或者任意数值类型
_ArrayLikeNumber_co = _DualArrayLike[
    dtype[Union[np.bool, number[Any]]],
    Union[bool, int, float, complex],
]

# 定义一个类型别名 _ArrayLikeTD64_co,表示时间差类型数组,可以包含布尔值、任意整数或者 timedelta64 类型
_ArrayLikeTD64_co = _DualArrayLike[
    dtype[Union[np.bool, integer[Any], timedelta64]],
    Union[bool, int],
]

# 定义一个类型别名 _ArrayLikeDT64_co,表示日期时间类型数组,可以是支持日期时间 dtype 的数组或者嵌套数组
_ArrayLikeDT64_co = Union[
    _SupportsArray[dtype[datetime64]],
    _NestedSequence[_SupportsArray[dtype[datetime64]]],
]

# 定义一个类型别名 _ArrayLikeObject_co,表示对象类型数组,可以是支持 object_ dtype 的数组或者嵌套数组
_ArrayLikeObject_co = Union[
    _SupportsArray[dtype[object_]],
    _NestedSequence[_SupportsArray[dtype[object_]]],
]

# 定义一个类型别名 _ArrayLikeVoid_co,表示空类型数组,可以是支持 void dtype 的数组或者嵌套数组
_ArrayLikeVoid_co = Union[
    _SupportsArray[dtype[void]],
    _NestedSequence[_SupportsArray[dtype[void]]],
]

# 定义一个类型别名 _ArrayLikeStr_co,表示字符串类型数组,可以包含 str_ dtype 或者普通字符串类型
_ArrayLikeStr_co = _DualArrayLike[
    dtype[str_],
    str,
]

# 定义一个类型别名 _ArrayLikeBytes_co,表示字节类型数组,可以包含 bytes_ dtype 或者普通字节串类型
_ArrayLikeBytes_co = _DualArrayLike[
    dtype[bytes_],
    bytes,
]

# 定义一个类型别名 _ArrayLikeInt,表示整数类型数组,可以包含任意整数类型
_ArrayLikeInt = _DualArrayLike[
    dtype[integer[Any]],
    int,
]

# 定义一个特殊类型 _UnknownType,用于处理 NDArray[Any],但不匹配任何具体类型
# 用作第一个重载,只匹配 NDArray[Any],而不匹配任何实际类型
# 参考:https://github.com/numpy/numpy/pull/22193
class _UnknownType:
    ...

# 定义一个类型别名 _ArrayLikeUnknown,表示未知类型数组,可以包含 _UnknownType 或者其 dtype 类型
_ArrayLikeUnknown = _DualArrayLike[
    dtype[_UnknownType],
    _UnknownType,
]

.\numpy\numpy\_typing\_callable.pyi

"""
A module with various ``typing.Protocol`` subclasses that implement
the ``__call__`` magic method.

See the `Mypy documentation`_ on protocols for more details.

.. _`Mypy documentation`: https://mypy.readthedocs.io/en/stable/protocols.html#callback-protocols

"""

# 导入必要的模块和类
from __future__ import annotations

from typing import (
    TypeVar,
    overload,
    Any,
    NoReturn,
    Protocol,
)

import numpy as np
from numpy import (
    generic,
    timedelta64,
    number,
    integer,
    unsignedinteger,
    signedinteger,
    int8,
    int_,
    floating,
    float64,
    complexfloating,
    complex128,
)
from ._nbit import _NBitInt, _NBitDouble
from ._scalars import (
    _BoolLike_co,
    _IntLike_co,
    _FloatLike_co,
    _NumberLike_co,
)
from . import NBitBase
from ._array_like import NDArray
from ._nested_sequence import _NestedSequence

# 定义类型变量
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
_T1_contra = TypeVar("_T1_contra", contravariant=True)
_T2_contra = TypeVar("_T2_contra", contravariant=True)
_2Tuple = tuple[_T1, _T1]

_NBit1 = TypeVar("_NBit1", bound=NBitBase)
_NBit2 = TypeVar("_NBit2", bound=NBitBase)

_IntType = TypeVar("_IntType", bound=integer)
_FloatType = TypeVar("_FloatType", bound=floating)
_NumberType = TypeVar("_NumberType", bound=number)
_NumberType_co = TypeVar("_NumberType_co", covariant=True, bound=number)
_GenericType_co = TypeVar("_GenericType_co", covariant=True, bound=generic)

# 定义 `_BoolOp` 协议,包含多个 `__call__` 方法的重载
class _BoolOp(Protocol[_GenericType_co]):
    @overload
    def __call__(self, other: _BoolLike_co, /) -> _GenericType_co: ...
    @overload  # 平台相关
    def __call__(self, other: int, /) -> int_: ...
    @overload
    def __call__(self, other: float, /) -> float64: ...
    @overload
    def __call__(self, other: complex, /) -> complex128: ...
    @overload
    def __call__(self, other: _NumberType, /) -> _NumberType: ...

# 定义 `_BoolBitOp` 协议,包含多个 `__call__` 方法的重载
class _BoolBitOp(Protocol[_GenericType_co]):
    @overload
    def __call__(self, other: _BoolLike_co, /) -> _GenericType_co: ...
    @overload  # 平台相关
    def __call__(self, other: int, /) -> int_: ...
    @overload
    def __call__(self, other: _IntType, /) -> _IntType: ...

# 定义 `_BoolSub` 协议,包含多个 `__call__` 方法的重载
class _BoolSub(Protocol):
    # 注意:这里没有 `other: bool`
    @overload
    def __call__(self, other: bool, /) -> NoReturn: ...
    @overload  # 平台相关
    def __call__(self, other: int, /) -> int_: ...
    @overload
    def __call__(self, other: float, /) -> float64: ...
    @overload
    def __call__(self, other: complex, /) -> complex128: ...
    @overload
    def __call__(self, other: _NumberType, /) -> _NumberType: ...

# 定义 `_BoolTrueDiv` 协议,包含多个 `__call__` 方法的重载
class _BoolTrueDiv(Protocol):
    @overload
    def __call__(self, other: float | _IntLike_co, /) -> float64: ...
    @overload
    def __call__(self, other: complex, /) -> complex128: ...
    @overload
    def __call__(self, other: _NumberType, /) -> _NumberType: ...

# 定义 `_BoolMod` 协议,包含多个 `__call__` 方法的重载
class _BoolMod(Protocol):
    @overload
    def __call__(self, other: _BoolLike_co, /) -> int8: ...
    # 使用 @overload 装饰器指定多个重载函数,具体实现因平台而异
    @overload  # platform dependent
    # 定义一个接受整数参数并返回整数类型结果的重载函数
    def __call__(self, other: int, /) -> int_: ...
    # 定义一个接受浮点数参数并返回浮点数类型结果的重载函数
    @overload
    def __call__(self, other: float, /) -> float64: ...
    # 定义一个接受 _IntType 类型参数并返回相同类型结果的重载函数
    @overload
    def __call__(self, other: _IntType, /) -> _IntType: ...
    # 定义一个接受 _FloatType 类型参数并返回相同类型结果的重载函数
    @overload
    def __call__(self, other: _FloatType, /) -> _FloatType: ...
class _BoolDivMod(Protocol):
    # 定义一个协议 _BoolDivMod,用于处理不同类型参数的除法和取模操作
    @overload
    def __call__(self, other: _BoolLike_co, /) -> _2Tuple[int8]: ...
    @overload  # 平台相关
    def __call__(self, other: int, /) -> _2Tuple[int_]: ...
    @overload
    def __call__(self, other: float, /) -> _2Tuple[floating[_NBit1 | _NBitDouble]]: ...
    @overload
    def __call__(self, other: _IntType, /) -> _2Tuple[_IntType]: ...
    @overload
    def __call__(self, other: _FloatType, /) -> _2Tuple[_FloatType]: ...


class _TD64Div(Protocol[_NumberType_co]):
    # 定义一个协议 _TD64Div,用于处理 timedelta64 类型的除法操作
    @overload
    def __call__(self, other: timedelta64, /) -> _NumberType_co: ...
    @overload
    def __call__(self, other: _BoolLike_co, /) -> NoReturn: ...
    @overload
    def __call__(self, other: _FloatLike_co, /) -> timedelta64: ...


class _IntTrueDiv(Protocol[_NBit1]):
    # 定义一个协议 _IntTrueDiv,用于处理整数类型的真除操作
    @overload
    def __call__(self, other: bool, /) -> floating[_NBit1]: ...
    @overload
    def __call__(self, other: int, /) -> floating[_NBit1 | _NBitInt]: ...
    @overload
    def __call__(self, other: float, /) -> floating[_NBit1 | _NBitDouble]: ...
    @overload
    def __call__(
        self, other: complex, /,
    ) -> complexfloating[_NBit1 | _NBitDouble, _NBit1 | _NBitDouble]: ...
    @overload
    def __call__(self, other: integer[_NBit2], /) -> floating[_NBit1 | _NBit2]: ...


class _UnsignedIntOp(Protocol[_NBit1]):
    # 定义一个协议 _UnsignedIntOp,用于处理无符号整数类型的操作
    # 注意:`uint64 + signedinteger -> float64`
    @overload
    def __call__(self, other: bool, /) -> unsignedinteger[_NBit1]: ...
    @overload
    def __call__(
        self, other: int | signedinteger[Any], /
    ) -> Any: ...
    @overload
    def __call__(self, other: float, /) -> floating[_NBit1 | _NBitDouble]: ...
    @overload
    def __call__(
        self, other: complex, /,
    ) -> complexfloating[_NBit1 | _NBitDouble, _NBit1 | _NBitDouble]: ...
    @overload
    def __call__(
        self, other: unsignedinteger[_NBit2], /
    ) -> unsignedinteger[_NBit1 | _NBit2]: ...


class _UnsignedIntBitOp(Protocol[_NBit1]):
    # 定义一个协议 _UnsignedIntBitOp,用于处理无符号整数类型的位操作
    @overload
    def __call__(self, other: bool, /) -> unsignedinteger[_NBit1]: ...
    @overload
    def __call__(self, other: int, /) -> signedinteger[Any]: ...
    @overload
    def __call__(self, other: signedinteger[Any], /) -> signedinteger[Any]: ...
    @overload
    def __call__(
        self, other: unsignedinteger[_NBit2], /
    ) -> unsignedinteger[_NBit1 | _NBit2]: ...


class _UnsignedIntMod(Protocol[_NBit1]):
    # 定义一个协议 _UnsignedIntMod,用于处理无符号整数类型的取模操作
    @overload
    def __call__(self, other: bool, /) -> unsignedinteger[_NBit1]: ...
    @overload
    def __call__(
        self, other: int | signedinteger[Any], /
    ) -> Any: ...
    @overload
    def __call__(self, other: float, /) -> floating[_NBit1 | _NBitDouble]: ...
    @overload
    def __call__(
        self, other: unsignedinteger[_NBit2], /
    ) -> unsignedinteger[_NBit1 | _NBit2]: ...


class _UnsignedIntDivMod(Protocol[_NBit1]):
    # 定义一个协议 _UnsignedIntDivMod,用于处理无符号整数类型的除法和取模操作
    @overload
    def __call__(self, other: bool, /) -> _2Tuple[signedinteger[_NBit1]]: ...
    @overload
    # 定义 __call__ 方法,使该类的实例可以被调用
    def __call__(
        self, other: int | signedinteger[Any], /
    ) -> _2Tuple[Any]: ...

    # __call__ 方法的重载,用于处理参数为 float 类型的情况
    @overload
    def __call__(self, other: float, /) -> _2Tuple[floating[_NBit1 | _NBitDouble]]: ...

    # __call__ 方法的重载,用于处理参数为 unsignedinteger 类型的情况
    @overload
    def __call__(
        self, other: unsignedinteger[_NBit2], /
    ) -> _2Tuple[unsignedinteger[_NBit1 | _NBit2]]: ...
class _SignedIntOp(Protocol[_NBit1]):
    # 定义 _SignedIntOp 协议,指定其支持的多态函数签名

    @overload
    def __call__(self, other: bool, /) -> signedinteger[_NBit1]: ...
    # 定义协议方法的重载:接受布尔类型参数,返回指定位数的有符号整数

    @overload
    def __call__(self, other: int, /) -> signedinteger[_NBit1 | _NBitInt]: ...
    # 定义协议方法的重载:接受整数类型参数,返回指定位数的有符号整数或整数类型

    @overload
    def __call__(self, other: float, /) -> floating[_NBit1 | _NBitDouble]: ...
    # 定义协议方法的重载:接受浮点数类型参数,返回指定位数的浮点数

    @overload
    def __call__(
        self, other: complex, /,
    ) -> complexfloating[_NBit1 | _NBitDouble, _NBit1 | _NBitDouble]: ...
    # 定义协议方法的重载:接受复数类型参数,返回指定位数的复数

    @overload
    def __call__(
        self, other: signedinteger[_NBit2], /,
    ) -> signedinteger[_NBit1 | _NBit2]: ...
    # 定义协议方法的重载:接受指定位数的有符号整数参数,返回指定位数的有符号整数

class _SignedIntBitOp(Protocol[_NBit1]):
    # 定义 _SignedIntBitOp 协议,指定其支持的多态函数签名

    @overload
    def __call__(self, other: bool, /) -> signedinteger[_NBit1]: ...
    # 定义协议方法的重载:接受布尔类型参数,返回指定位数的有符号整数

    @overload
    def __call__(self, other: int, /) -> signedinteger[_NBit1 | _NBitInt]: ...
    # 定义协议方法的重载:接受整数类型参数,返回指定位数的有符号整数或整数类型

    @overload
    def __call__(
        self, other: signedinteger[_NBit2], /,
    ) -> signedinteger[_NBit1 | _NBit2]: ...
    # 定义协议方法的重载:接受指定位数的有符号整数参数,返回指定位数的有符号整数

class _SignedIntMod(Protocol[_NBit1]):
    # 定义 _SignedIntMod 协议,指定其支持的多态函数签名

    @overload
    def __call__(self, other: bool, /) -> signedinteger[_NBit1]: ...
    # 定义协议方法的重载:接受布尔类型参数,返回指定位数的有符号整数

    @overload
    def __call__(self, other: int, /) -> signedinteger[_NBit1 | _NBitInt]: ...
    # 定义协议方法的重载:接受整数类型参数,返回指定位数的有符号整数或整数类型

    @overload
    def __call__(self, other: float, /) -> floating[_NBit1 | _NBitDouble]: ...
    # 定义协议方法的重载:接受浮点数类型参数,返回指定位数的浮点数

    @overload
    def __call__(
        self, other: signedinteger[_NBit2], /,
    ) -> signedinteger[_NBit1 | _NBit2]: ...
    # 定义协议方法的重载:接受指定位数的有符号整数参数,返回指定位数的有符号整数

class _SignedIntDivMod(Protocol[_NBit1]):
    # 定义 _SignedIntDivMod 协议,指定其支持的多态函数签名

    @overload
    def __call__(self, other: bool, /) -> _2Tuple[signedinteger[_NBit1]]: ...
    # 定义协议方法的重载:接受布尔类型参数,返回一个元组,包含两个指定位数的有符号整数

    @overload
    def __call__(self, other: int, /) -> _2Tuple[signedinteger[_NBit1 | _NBitInt]]: ...
    # 定义协议方法的重载:接受整数类型参数,返回一个元组,包含两个指定位数的有符号整数或整数类型

    @overload
    def __call__(self, other: float, /) -> _2Tuple[floating[_NBit1 | _NBitDouble]]: ...
    # 定义协议方法的重载:接受浮点数类型参数,返回一个元组,包含两个指定位数的浮点数

    @overload
    def __call__(
        self, other: signedinteger[_NBit2], /,
    ) -> _2Tuple[signedinteger[_NBit1 | _NBit2]]: ...
    # 定义协议方法的重载:接受指定位数的有符号整数参数,返回一个元组,包含两个指定位数的有符号整数

class _FloatOp(Protocol[_NBit1]):
    # 定义 _FloatOp 协议,指定其支持的多态函数签名

    @overload
    def __call__(self, other: bool, /) -> floating[_NBit1]: ...
    # 定义协议方法的重载:接受布尔类型参数,返回指定位数的浮点数

    @overload
    def __call__(self, other: int, /) -> floating[_NBit1 | _NBitInt]: ...
    # 定义协议方法的重载:接受整数类型参数,返回指定位数的浮点数或整数类型

    @overload
    def __call__(self, other: float, /) -> floating[_NBit1 | _NBitDouble]: ...
    # 定义协议方法的重载:接受浮点数类型参数,返回指定位数的浮点数

    @overload
    def __call__(
        self, other: complex, /,
    ) -> complexfloating[_NBit1 | _NBitDouble, _NBit1 | _NBitDouble]: ...
    # 定义协议方法的重载:接受复数类型参数,返回指定位数的复数

    @overload
    def __call__(
        self, other: integer[_NBit2] | floating[_NBit2], /
    ) -> floating[_NBit1 | _NBit2]: ...
    # 定义协议方法的重载:接受指定位数的整数或浮点数类型参数,返回指定位数的浮点数

class _FloatMod(Protocol[_NBit1]):
    # 定义 _FloatMod 协议,指定其支持的多态函数签名

    @overload
    def __call__(self, other: bool, /) -> floating[_NBit1]: ...
    # 定义协议方法的重载:接受布尔类型参数,返回指定位数的浮点数

    @overload
    def __call__(self, other: int, /) -> floating[_NBit1 | _NBitInt]: ...
    # 定义协议方法的重载:接受整数类型参数,返回指定位数的浮点数或整数类型

    @overload
    def __call__(self, other: float, /) -> floating[_NBit1 | _NBitDouble]: ...
    # 定义协议方法的重载:接受浮点数类型参数,返回指定位数的浮点数

    @overload
    def __call__(
        self, other: integer[_NBit2] | floating[_NBit2], /
    ) -> floating[_NBit1 | _NBit2]: ...
    # 定义协议方法的重载:接受指定位数的整数或浮点数类型参数,返回指定位数的浮点数

class _FloatDivMod(Protocol[_NBit1]):
    # 定义 _FloatDivMod 协议,指定其支持的多态函数签
    # 定义 __call__ 方法,使对象可以被调用
    def __call__(self, other: int, /) -> _2Tuple[floating[_NBit1 | _NBitInt]]: ...
    # 重载 __call__ 方法,支持参数类型为 float 的调用
    @overload
    def __call__(self, other: float, /) -> _2Tuple[floating[_NBit1 | _NBitDouble]]: ...
    # 重载 __call__ 方法,支持参数类型为 integer 或 floating 的调用,参数类型为 _NBit2
    @overload
    def __call__(
        self, other: integer[_NBit2] | floating[_NBit2], /
    ) -> _2Tuple[floating[_NBit1 | _NBit2]]: ...
# 定义一个复杂运算的协议 `_ComplexOp`
class _ComplexOp(Protocol[_NBit1]):
    # 重载:接受布尔类型参数,返回复数浮点数
    @overload
    def __call__(self, other: bool, /) -> complexfloating[_NBit1, _NBit1]: ...
    
    # 重载:接受整数参数,返回复数浮点数
    @overload
    def __call__(self, other: int, /) -> complexfloating[_NBit1 | _NBitInt, _NBit1 | _NBitInt]: ...
    
    # 重载:接受复数参数,返回复数浮点数
    @overload
    def __call__(
        self, other: complex, /,
    ) -> complexfloating[_NBit1 | _NBitDouble, _NBit1 | _NBitDouble]: ...
    
    # 重载:接受整数、浮点数或复数参数,返回复数浮点数
    @overload
    def __call__(
        self,
        other: (
            integer[_NBit2]
            | floating[_NBit2]
            | complexfloating[_NBit2, _NBit2]
        ), /,
    ) -> complexfloating[_NBit1 | _NBit2, _NBit1 | _NBit2]: ...

# 定义一个数字操作的协议 `_NumberOp`
class _NumberOp(Protocol):
    # 重载:接受 `_NumberLike_co` 类型的参数,返回任意类型
    def __call__(self, other: _NumberLike_co, /) -> Any: ...

# 定义支持小于比较的协议 `_SupportsLT`
class _SupportsLT(Protocol):
    # 方法:小于比较,接受任意类型参数,返回对象
    def __lt__(self, other: Any, /) -> object: ...

# 定义支持大于比较的协议 `_SupportsGT`
class _SupportsGT(Protocol):
    # 方法:大于比较,接受任意类型参数,返回对象
    def __gt__(self, other: Any, /) -> object: ...

# 定义比较操作的协议 `_ComparisonOp`,参数类型为 `_T1_contra` 和 `_T2_contra`
class _ComparisonOp(Protocol[_T1_contra, _T2_contra]):
    # 重载:接受 `_T1_contra` 类型参数,返回 NumPy 布尔类型
    @overload
    def __call__(self, other: _T1_contra, /) -> np.bool: ...
    
    # 重载:接受 `_T2_contra` 类型参数,返回 NumPy 布尔数组
    @overload
    def __call__(self, other: _T2_contra, /) -> NDArray[np.bool]: ...
    
    # 重载:接受 `_SupportsLT` 或 `_SupportsGT` 或 `_NestedSequence[_SupportsLT | _SupportsGT]` 参数,
    # 返回任意类型
    @overload
    def __call__(
        self,
        other: _SupportsLT | _SupportsGT | _NestedSequence[_SupportsLT | _SupportsGT],
        /,
    ) -> Any: ...