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_cast、promote_types、min_scalar_type、result_type、common_type | 类型转换可行性判断与类型提升 |
| Creating data types(创建类型) | dtype、rec.format_parser | 构造 dtype 对象、解析格式字符串 |
| Data type information(类型信息) | finfo、iinfo | 浮点与整型的机器限制 |
| Data type testing(类型测试) | isdtype、issubdtype | 判断类型归属与层次关系 |
| Miscellaneous(杂项) | typename、mintypecode | 类型名描述与最小类型字符 |
这些函数并非分散在不同模块:从仓库源码看,can_cast、min_scalar_type、result_type定义在 numpy/_core/multiarray.py(Python 分发层,通过array_function_from_c_func_and_dispatcher包装_multiarray_umath中的 C 实现);isdtype、issubdtype定义在 numpy/_core/numerictypes.py;finfo、iinfo定义在 numpy/_core/getlimits.py;typename、mintypecode、common_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 标量3与int8数组的结果仍是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); - 除
int64、uint64之外的所有输入都能无损转换为返回值。
从实现看(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_type或np.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中:对于object与bool类型不附加位数后缀,其他类型会追加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).dtype为float32)。
核心属性(见 getlimits.py#L58-L110):
| 属性 | 含义 |
|---|---|
bits | 类型占用的位数 |
dtype | 对应的 dtype;复数输入返回其分量的浮点 dtype |
eps | 1.0 与下一个更大可表示浮点数之差(IEEE-754 双精度下为2**-52≈ 2.22e-16) |
epsneg | 1.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 |
tiny | smallest_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,返回整型类型的机器限制,属性简洁:bits、dtype、min、max。实现上(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:若
typechars与typeset无交集时返回的默认字符(默认'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,给出几个实用的选型准则:
- 问"能不能转换"→ 用
can_cast,务必理解casting五档(no/equiv/safe/same_kind/unsafe)的递进关系; - 问"运算结果是什么类型"→ 用
result_type(多操作数)或promote_types(两操作数),注意 NumPy 2.0 起标量不再影响结果类型; - 想按实际值压缩存储→ 用
min_scalar_type找出能容纳标量值的最小 dtype; - 想统一一组数组的公共类型(强制浮点)→ 用
common_type,但要记住它只接受数组且结果恒为浮点/复数; - 查询机器限制→ 浮点用
finfo(含eps、max、smallest_normal等全套属性),整型用iinfo(min/max/bits); - 判断类型归属→ 沿类型层次判断用
issubdtype,按语义种类(如'real floating'、'integral')判断用isdtype; - 构造结构化 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),仅供参考