NumPy Data Type Routines 全解:类型判定、提升与信息查询
2026/9/20 20:55:34 网站建设 项目流程

NumPy Data Type Routines 全解:类型判定、提升与信息查询

【免费下载链接】numpyThe fundamental package for scientific computing with Python.项目地址: https://gitcode.com/gh_mirrors/nu/numpy

导读

本文基于 NumPy 官方参考文档中的 Data type routines 章节,系统讲解 NumPy 数据类型(dtype)例程的五大分类:类型判定(can_cast)、类型提升(promote_types/result_type/min_scalar_type/common_type)、数据类型创建(dtype/rec.format_parser)、机器信息查询(finfo/iinfo)以及类型测试与杂项工具(isdtype/issubdtype/typename/mintypecode)。读完本文,你将掌握每个例程的完整签名、参数语义、返回规则与典型用法,并能结合仓库源码理解其底层实现位置与设计动机。

一、Data type routines 总览

NumPy 官方参考将 dtype 相关的例程分为五组,本文按此骨架展开:

分类例程功能
Data type routines(类型例程)can_castpromote_typesmin_scalar_typeresult_typecommon_type类型转换可行性判断与类型提升
Creating data types(创建类型)dtyperec.format_parser构造 dtype 对象、解析格式字符串
Data type information(类型信息)finfoiinfo浮点与整型的机器限制
Data type testing(类型测试)isdtypeissubdtype判断类型归属与层次关系
Miscellaneous(杂项)typenamemintypecode类型名描述与最小类型字符

这些函数并非分散在不同模块:从仓库源码看,can_castmin_scalar_typeresult_type定义在 numpy/_core/multiarray.py(Python 分发层,通过array_function_from_c_func_and_dispatcher包装_multiarray_umath中的 C 实现);isdtypeissubdtype定义在 numpy/_core/numerictypes.py;finfoiinfo定义在 numpy/_core/getlimits.py;typenamemintypecodecommon_type则位于 numpy/lib/_type_check_impl.py。理解这一布局,有助于在需要深挖实现时快速定位代码。

二、类型判定:can_cast 与 casting 规则

2.1 函数签名

can_cast(from_, to, casting="safe")用于判断"从类型from_转换到类型to是否符合给定的 casting 规则",返回布尔值。其声明位于 numpy/_core/multiarray.py#L604,参数含义:

  • from_:源类型,可以是 dtype、dtype 说明符、NumPy 标量或数组;
  • to:目标类型,dtype 或 dtype 说明符;
  • casting:控制允许的转换种类,取值如下:
casting 取值含义
'no'完全不允许任何类型转换
'equiv'仅允许字节序(byte-order)变化
'safe'仅允许能保值的转换
'same_kind'允许 safe 转换,或同一种类内部的转换(如 float64 → float32)
'unsafe'允许任意数据转换

2.2 典型示例

import numpy as np np.can_cast(np.int32, np.int64) # True,保值的加宽转换 np.can_cast(np.float64, complex) # True,float64 → complex128 可保值 np.can_cast(complex, float) # False,复数转浮点可能丢失虚部 np.can_cast('i8', 'f8') # True,int64 → float64(注意大整数可能有精度损失) np.can_cast('i8', 'f4') # False,int64 → float32 不保证保值 np.can_cast('i4', 'S4') # False,数值与字符串之间不能 safe 转换

2.3 版本行为说明(NumPy 2.0 起)

源码 docstring 明确标注了 2.0 的行为变化(见 multiarray.py#L634-L636):

versionchanged:: 2.0:该函数不再支持 Python 标量,也不再对 0 维数组和 NumPy 标量应用任何基于值(value-based)的逻辑。

也就是说,在 NumPy 2.x 中can_cast的判断完全基于 dtype 本身,而非传入的具体数值,这是理解该函数现代语义的关键。

三、类型提升:promote_types、result_type、min_scalar_type、common_type

3.1 promote_types:两个类型的提升结果

promote_types(type1, type2)返回对两个输入类型应用提升规则后得到的结果 dtype,其类型签名(__type1: DTypeLike, __type2: DTypeLike -> dtype)可参考 numpy/_core/multiarray.pyi#L2700,底层实现位于_multiarray_umath扩展模块。它只接受两个操作数,适合用于"两个数组相运算的结果类型"这类场景。

np.promote_types(np.int8, np.uint16) # dtype('int32') np.promote_types(np.float32, np.int64) # dtype('float64')

3.2 result_type:任意多个操作数的提升结果

result_type(*arrays_and_dtypes)接收任意数量的数组与 dtype,返回应用 NumPy 类型提升规则(见参考文档 arrays.promotion)后的结果类型,声明位于 multiarray.py#L714。它是promote_types的多操作数推广,也是最贴近实际运算语义的提升查询工具:

np.result_type(3, np.arange(7, dtype=np.int8)) # dtype('int8'),小标量不会抬高结果类型 np.result_type(np.int32, np.complex64) # dtype('complex128') np.result_type(3.0, -2) # dtype('float64')

注意第一个例子:Python 标量3int8数组的结果仍是int8,这是"标量不提升结果类型"规则的体现(2.0 起不再有 value-based promotion)。

3.3 min_scalar_type:容纳一个值的最小类型

min_scalar_type(a)对标量a返回能容纳其值的"最小尺寸、最小种类"的 dtype;对非标量数组则原样返回数组的 dtype。声明位于 multiarray.py#L666,并有两条重要规则:浮点数不会下沉为整数,复数不会下沉为浮点数。

np.min_scalar_type(10) # dtype('uint8') np.min_scalar_type(-260) # dtype('int16'),负数需要带符号类型 np.min_scalar_type(3.1) # dtype('float16'),浮点值保持浮点种类 np.min_scalar_type(1e50) # dtype('float64'),超出 float16/float32 范围 np.min_scalar_type(np.arange(4, dtype=np.float64)) # dtype('float64'),数组原样返回

该函数常与result_type配合使用,例如根据实际数值动态选择紧凑的存储 dtype。

3.4 common_type:数组的公共标量类型

common_type(*arrays)位于 numpy/lib/_type_check_impl.py#L666,返回输入数组的公共标量类型(注意是标量类型np.float32这类 class,而非 dtype)。其规则与前述提升函数不同:

  • 返回值永远是"不精确"(inexact)的浮点标量类型,即使输入全是整型数组;
  • 只要出现整型数组,最小精度也是 64 位浮点(float64);
  • int64uint64之外的所有输入都能无损转换为返回值。

从实现看(L702-L725),它遍历数组:整型统一映射到float64精度,其余按array_precision表取最高精度;只要任一输入是复数对象,结果就落在复数分支。示例:

np.common_type(np.arange(2, dtype=np.float32)) # numpy.float32 np.common_type(np.arange(2, dtype=np.float32), np.arange(2)) # numpy.float64(整型参与 → float64) np.common_type(np.arange(4), np.array([45, 6.j]), np.array([45.0])) # numpy.complex128

需要强调:common_type只接受数组输入。源码中,若输入不是数组会抛出TypeError,并明确提示"对 dtype 或标量类型求公共类型请使用np.result_typenp.promote_types"——这正是它与提升函数分工的边界。

四、创建数据类型:dtype 与 rec.format_parser

4.1 dtype:一切类型的入口

dtype是 NumPy 中最核心的构造器,接受类型对象、类型字符、字符串说明符、元组(如(base, shape)子数组)、字典(含names/formats/offsets/titles/itemsize/aligned键)等,返回一个 dtype 实例。其关键属性包括kind(种类字符,如'i''f''c''b''S''U''V''O')、itemsize(字节数)与name

name属性的实现细节在 numpy/_core/_dtype.py#L338-L361 的_name_get中:对于objectbool类型不附加位数后缀,其他类型会追加itemsize * 8的位宽,datetime 类型还会追加时间单元元数据(如datetime64[ns])。这也是 NumPy 2.5 弃用numpy.typename、建议改用dtype.name的原因——后者给出的就是这种"位名称"。

np.dtype(np.int32).name # 'int32' np.dtype('f8').name # 'float64' np.dtype('datetime64[ns]').name # 'datetime64[ns]'

4.2 rec.format_parser:把格式串解析为结构化 dtype

rec.format_parser是 numpy/_core/records.py#L57 中定义的类,负责把"格式、字段名、标题"描述转换为结构化 dtype。构造完成后,结果通过.dtype属性获取:

dtype = np.rec.format_parser(formats, names, titles).dtype

参数说明(完整定义见 records.py#L70-L92):

  • formats:格式描述,可以是逗号分隔的字符串(如'f8, i4, S5'),也可以是格式字符串列表(如['f8', 'i4', 'S5']);
  • names:字段名,逗号分隔字符串或字符串列表/元组;传空列表时使用默认字段名('f0', 'f1', ...)
  • titles:标题字符串序列,空列表表示不设置标题;
  • aligned(可选,默认False):为True时按 C 编译器的方式填充对齐字段;
  • byteorder(可选):指定后所有字段统一改为该字节序,可用说明符参见dtype.newbyteorder
>>> import numpy as np >>> parser = np.rec.format_parser(['<f8', '<i4'], ['col1', 'col2']) >>> parser.dtype dtype({'names': ['col1', 'col2'], 'formats': ['<f8', '<i4'], 'titles': ['col1', 'col2'], 'offsets': [0, 8], 'itemsize': 16})

五、数据类型信息:finfo 与 iinfo

5.1 finfo:浮点类型的机器限制

finfo(dtype)定义在 numpy/_core/getlimits.py#L52,返回浮点(或复数浮点)类型的机器限制对象。它支持复数输入:此时返回的是对应实部浮点类型的信息(如np.finfo(np.complex64).dtypefloat32)。

核心属性(见 getlimits.py#L58-L110):

属性含义
bits类型占用的位数
dtype对应的 dtype;复数输入返回其分量的浮点 dtype
eps1.0 与下一个更大可表示浮点数之差(IEEE-754 双精度下为2**-52≈ 2.22e-16)
epsneg1.0 与下一个更小可表示浮点数之差(双精度下为2**-53≈ 1.11e-16)
iexp/nexp指数部分位数 / 含符号与偏置的指数位数
machep/negep产生eps/epsneg的指数
max/min最大可表示数 / 最小可表示数(通常为-max
maxexp/minexp溢出对应指数(C 标准 MAX_EXP)/ 无前导 0 的最负指数(MIN_EXP - 1)
nmant尾数显式位数(不含规格化数的隐式前导位)
precision该浮点类型近似可精确表示的十进制位数
resolution近似十进制分辨率,即10**-precision
tinysmallest_normal的向后兼容别名
smallest_normal最小的正规格化浮点数
smallest_subnormal最小的正非规格化(subnormal)浮点数

文档 Notes 还提醒开发者(getlimits.py#L124-L129):不要在模块顶层实例化finfo,因为首次计算开销较大、会拖慢导入;对象本身有缓存,在函数内反复调用没有问题。

np.finfo(np.float64).dtype # dtype('float64') np.finfo(np.complex64).dtype # dtype('float32') np.finfo(np.float32).eps # 1.1920929e-07 np.finfo(np.float64).max # 1.7976931348623157e+308

longdouble,其表示因平台而异:多数平台是 IEEE-754 的 binary128(四精度)或 binary64-extended(80 位扩展精度),而 PowerPC 上可能是 IBM double-double 格式(一对 float64),精度与范围特性特殊(见 getlimits.py#L137-L141)。

5.2 iinfo:整型类型的机器限制

iinfo(int_type)定义在 getlimits.py#L342,返回整型类型的机器限制,属性简洁:bitsdtypeminmax。实现上(L399-L434):bits = itemsize * 8,无符号类型最小值为 0、最大值为(1 << bits) - 1,有符号类型最小值为-(1 << (bits-1))、最大值为(1 << (bits-1)) - 1;输入非整型种类(kind不是'i''u')时抛出ValueError

np.iinfo(np.int16).min # -32768 np.iinfo(np.int16).max # 32767 np.iinfo(np.uint8).max # 255 np.iinfo(np.int32(10)).min # -2147483648,也接受标量实例

六、数据类型测试:isdtype 与 issubdtype

6.1 issubdtype:类型层次包含关系

issubdtype(arg1, arg2)是内置issubclass在 dtype 上的对应物,定义在 numpy/_core/numerictypes.py#L419。它沿 NumPy 的类型层次(hierarchy)判断arg1是否为arg2的子类型。类型层次全貌见该模块顶部的文档注释(numerictypes.py#L40-L77):

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

行为要点(含 docstring 示例):

np.issubdtype(np.int32, np.integer) # True np.issubdtype(np.float32, np.integer) # False np.issubdtype(np.float32, np.floating)# True np.issubdtype(np.float64, np.float32) # False,不同位宽互不为子类型 np.issubdtype('S1', np.bytes_) # True,dtype-like 对象也可用 np.issubdtype('i4', np.signedinteger) # True

实现上(L476-L481),非generic子类的参数会被dtype(arg).type归一化为标量类型,再做issubclass判断。

6.2 isdtype:按语义种类判断类型

isdtype(dtype, kind)定义在 numerictypes.py#L329,用于判断给定 dtype 是否属于指定的"种类(kind)"。目前仅支持 NumPy 内置 dtype,第三方 dtype 尚不支持kind参数可以是 dtype、字符串、或它们的元组,合法的字符串种类为:

kind 字符串含义
'bool'布尔类型
'signed integer'有符号整型
'unsigned integer'无符号整型
'integral'整型(有符号 + 无符号)
'real floating'实浮点类型
'complex floating'复数浮点类型
'numeric'数值类型(整型 + 浮点 + 复数)

实现上(L377-L415),字符串种类会被展开为sctypes中的具体类型集合;未知字符串抛出ValueError,非 NumPy dtype 参数抛出TypeError

np.isdtype(np.float32, np.float64) # False,具体 dtype 之间是精确匹配 np.isdtype(np.float32, "real floating") # True np.isdtype(np.complex128, ("real floating", "complex floating")) # True,元组取并集 np.isdtype(np.int32, "integral") # True np.isdtype(np.uint8, "signed integer") # False

七、杂项:typename 与 mintypecode

7.1 mintypecode:最小安全转换类型字符

mintypecode(typechars, typeset='GDFgdf', default='d')定义在 numpy/lib/_type_check_impl.py#L27,返回"能安全容纳给定所有类型数据的最小尺寸类型"的类型字符。

  • typechars:类型字符列表;若传入 array_like,则使用其dtype.char
  • typeset:候选返回字符集合,默认'GDFgdf'(长双精度复数/双精度复数/单精度复数/长双精度/双精度/单精度);
  • default:若typecharstypeset无交集时返回的默认字符(默认'd')。

实现上有特殊规则(L71-L78):若交集中同时出现'F''d',直接返回'D'(因为单精度复数与双精度实数并存时必须提升到双精度复数);否则按_typecodes_by_elsize的元素大小序取最小值。

np.mintypecode(['d', 'f', 'S']) # 'd' np.mintypecode(np.array([1.1, 2-3.j])) # 'D',复数输入 np.mintypecode('abceh', default='G') # 'G',无交集时返回默认值

7.2 typename:类型字符的描述文本(已弃用)

typename(char)返回类型字符的人类可读描述,定义于 _type_check_impl.py#L585。例如'd''double precision''F''complex single precision''?''bool''S''string''V''void'

注意:该函数已在 NumPy 2.5 标记为弃用(DeprecationWarning),官方建议改用numpy.dtype.name(见 L589-L590)。原因正如 4.1 节 所述:dtype.name通过 numpy/_core/_dtype.py 的_name_get直接给出"位名称",无需维护独立的字符映射表,也更准确。

八、实践要点与选型建议

综合以上 API,给出几个实用的选型准则:

  1. 问"能不能转换"→ 用can_cast,务必理解casting五档(no/equiv/safe/same_kind/unsafe)的递进关系;
  2. 问"运算结果是什么类型"→ 用result_type(多操作数)或promote_types(两操作数),注意 NumPy 2.0 起标量不再影响结果类型;
  3. 想按实际值压缩存储→ 用min_scalar_type找出能容纳标量值的最小 dtype;
  4. 想统一一组数组的公共类型(强制浮点)→ 用common_type,但要记住它只接受数组且结果恒为浮点/复数;
  5. 查询机器限制→ 浮点用finfo(含epsmaxsmallest_normal等全套属性),整型用iinfomin/max/bits);
  6. 判断类型归属→ 沿类型层次判断用issubdtype,按语义种类(如'real floating''integral')判断用isdtype
  7. 构造结构化 dtype→ 直接使用np.dtype,或通过np.rec.format_parser从格式串批量解析字段。

上述全部函数均由本仓库官方文档 routines.dtype.rst 收录,每个函数在generated/下还有独立页面;源码实现与类型层次图分别位于 multiarray.py、numerictypes.py、getlimits.py 与 lib/_type_check_impl.py,可随时深入查阅以验证行为细节。

【免费下载链接】numpyThe fundamental package for scientific computing with Python.项目地址: https://gitcode.com/gh_mirrors/nu/numpy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询