news 2026/9/17 4:08:59

Daft 类型转换完全指南:DataType 与 Python 类型之间的双向映射机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Daft 类型转换完全指南:DataType 与 Python 类型之间的双向映射机制

Daft 类型转换完全指南:DataType 与 Python 类型之间的双向映射机制

【免费下载链接】DaftHigh-performance data engine for AI and multimodal workloads. Process images, audio, video, and structured data at any scale项目地址: https://gitcode.com/GitHub_Trending/da/Daft

本文围绕 Daft 官方文档 Type Conversions 展开,系统讲解 Daft DataType 与 Python 类型之间的双向转换规则:Daft 到 Python 的取值映射(如Series.to_pylist)、Python 类型到 Daft 类型的静态推断(如@daft.func的返回类型提示)、以及基于 Python 对象字面值的运行时推断(如daft.from_pydict)。读完本文,你将能够准确预测任意 Python 类型/对象在 Daft 中被映射为哪种 DataType,也能结合 daft/datatype.py 的源码实现理解各推断分支的边界条件与警告行为。

Daft 到 Python:取值时的类型映射

当你从 Daft 数据中取出 Python 值时(典型场景包括 [Series.to_pylist][daft.series.Series.to_pylist]、将列 [cast][daft.expressions.Expression.cast] 到 Python 类型、以及传递给@daft.func装饰函数的参数),Daft DataType 按如下规则映射为 Python 类型:

Daft DataTypePython Type
NullNone
Booleanbool
Utf8str
Binary
FixedSizeBinary
bytes
Int8
Uint8
Int16
UInt16
Int32
UInt32
Int64
UInt64
int
Timestampdatetime.datetime
Datedatetime.date
Timedatetime.time
Durationdatetime.timedelta
Intervalnot supported
Float32
Float64
float
Decimal128decimal.Decimal
List[T]
FixedSizeList[T, n]
list[T]
Struct[k1: T1, k2: T2, ...]{ "k1": <T1>, "k2": <T2>, ... }
Map[K, V]list[tuple[K, V]](默认);maps_as_pydicts下为dict[K, V]
Tensor[T]
FixedShapeTensor[T, [...]]
numpy.typing.NDArray[T]
SparseTensor[T]
FixedShapeSparseTensor[T, [...]]
{
"values": <T>,
"indices": [<int>],
"shape": [<int>]
}
Embedding[T]numpy.typing.NDArray[T]
Imagenumpy.typing.NDArray[numpy.uint8 \| numpy.uint16 \| numpy.float32]
PythonAny
Extension[T]T

从源码结构看,上述行为对应 Rust 侧impl IntoPyObject for Literal的实现,入口位于 src/daft-core/src/lit/python.rs(文档中的注释即要求该表与 Rust 的Literal转 Python 对象行为保持一致)。

Map 类型的两种取值模式:maps_as_pydicts

Map[K, V]列取 Python 值时,Daft 默认转换为list[tuple[K, V]](关联列表),目的是保留重复键与键的顺序。若希望得到 Pythondict,可在Series.to_pylist等接口上传入maps_as_pydicts参数:

  • maps_as_pydicts="lossy":遇到重复键时保留最后一个值,并发出警告;
  • maps_as_pydicts="strict":遇到重复键时直接抛出异常

该参数在 Python 层的签名与文档位于 daft/series.py#L231-L241,底层由self._series.to_pylist(maps_as_pydicts)转发给 Rust 实现完成实际转换。选择建议:如果下游逻辑依赖"每个键唯一"的 dict 语义且能容忍静默丢失,用"lossy";如果数据源保证键唯一、或需要尽早暴露脏数据,用"strict"更稳妥。

Python 类型到 Daft:静态类型推断

当 Daft 需要根据Python 类型(而非具体值)推导 DataType 时——例如从@daft.func装饰函数的类型注解推断返回列的类型——使用的是DataType.infer_from_type类方法。你可以直接调用它来验证任意 Python 类型的推断结果:

Python TypeDaft DataType
NoneTypeNull
boolBoolean
strUtf8
bytesBinary
intInt64
floatFloat64
datetime.datetimeTimestamp[us]
datetime.dateDate
datetime.timeTime[us]
datetime.timedeltaDuration[us]
list[T]List[T]
dict[K, V]Map[K, V]
typing.TypedDict("...", { "k1": T1, "k2": T2, ... })Struct[k1: T1, k2: T2, ...]
tuple[T0, T1, ..., TN](实际类型中不含省略号)Struct[_0: T0, _1: T1, ..., _N: TN]
tuple[T, ...]List[T]
带序列化字段f1: T1,f2: T2, ... 的pydantic.BaseModelStruct[f1: T1, f2: T2, ...]
numpy.ndarray
torch.Tensor
tensorflow.Tensor
jax.Array
cupy.ndarray
Tensor[Python]
numpy.typing.NDArray[T]Tensor[T]
torch.FloatTensorTensor[Float32]
torch.DoubleTensorTensor[Float64]
torch.ByteTensorTensor[UInt8]
torch.CharTensorTensor[Int8]
torch.ShortTensorTensor[Int16]
torch.IntTensorTensor[Int32]
torch.LongTensorTensor[Int64]
torch.BoolTensorTensor[Boolean]
jaxtyping类型(见下文 jaxtyping 小节)Tensor 或 FixedShapeTensor
numpy.bool_Boolean
numpy.int8Int8
numpy.uint8UInt8
numpy.int16Int16
numpy.uint32/numpy.uint64等对应 numpy 整型UInt32 / UInt64 等
numpy.float32Float32
numpy.float64Float64
numpy.datetime64Timestamp[us]
pandas.SeriesList[Python]
PIL.Image.ImageImage[MIXED]
daft.SeriesList[Python]
其他所有类型Python

推断实现的关键分支(源码解读)

infer_from_type的完整实现位于 daft/datatype.py#L183-L404,其中几个容易被忽略的分支值得注意:

  • Union 类型:先对 Union 的每个成员递归推断。若所有成员推断出同一种 DataType,则取之;若是Optional[X](即Union[NoneType, X]),则退化为X;否则兜底为Python类型。
  • TypedDict 与 dict 的区别dict[K, V]推断为Map[K, V],因为仅从类型上无法得到具体的字段名;而TypedDict的键是已知的,因此能推断为Struct。源码中若发现 TypedDict 的键不是字符串,会降级为Map[Python, Python]并告警。
  • tuple 的两种形态tuple[int, str]这类定长元组映射为Struct[_0: ..., _1: ...](字段名为自动生成的下标);而tuple[T, ...](带省略号的无限元组)则映射为List[T]
  • Pydantic V2 支持:对pydantic.BaseModel的推断仅支持 Pydantic V2(源码中显式校验2.0.0 <= version < 3.0.0),并按model_configserialize_by_alias决定 Struct 字段名取别名还是属性名,同时会把model_computed_fields(computed field)也纳入 Struct 字段。
  • Tensor 类型族的精确匹配torch的 7 种具名 Tensor 子类各自映射到对应 dtype;而泛化的torch.Tensortensorflow.Tensorjax.Arraycupy.ndarray由于无法在类型层面得到 dtype,统一推断为Tensor[Python]。numpy 侧,NDArray[T]的第二个类型参数会被解出并映射为内层 dtype,解不出来时告警并回退Tensor[Python]
  • 无法静态推断的兜底decimal.Decimal类型(无法从类型得到 precision/scale)、裸的pandas.Seriesdaft.Series都会发出警告并回退为PythonList[Python];表外的任意类型一律落到Python类型分支。

jaxtyping:从注解中推断 dtype 与 shape

jaxtyping 库为 NumPy、PyTorch、TensorFlow、JAX 的数组类型提供 dtype 与 shape 注解。Daft 可以原生解析jaxtyping注解,同时推断出张量的内层 dtype 和形状。对应实现是 daft/datatype.py 中的_infer_from_jaxtyping

示例:

  • jaxtyping.Float64[jaxtyping.Array, "1 2 3 4"]FixedShapeTensor[Float64, [1, 2, 3, 4]]
  • jaxtyping.Int8[torch.Tensor, "dim1 dim2"]Tensor[Int8]

Dtype 推断

jaxtyping TypeDaft DataType
BoolBoolean
Int8Int8
UInt8UInt8
Int16Int16
UInt16UInt16
Int32Int32
UInt32UInt32
Int64
Int
Integer
Int64
UInt64
UInt
UInt64
Float32Float32
Float64
Float
Real
Float64
Everything elsePython

注:这里得到的 DataType 是结果Tensor/FixedShapeTensor内层类型

Shape 推断

jaxtyping类型的第二个泛型参数是一个空格分隔的符号字符串,表示数组形状。Daft 的推断策略(与源码中"仅当所有维度都是固定值_FixedDim时才写入 shape"的逻辑一致):

  • 若所有维度均为固定尺寸,推断为FixedShapeTensor,例如"1 2 3""rows=4 cols=3"""(标量形状);
  • 否则推断为Tensor,例如"dim1 dim2""512 512 _""... 1 2 3"

Python 对象到 Daft:运行时值推断

除了上表的类型级映射,Daft 在未显式指定类型、直接把 Python 对象转换为 Daft 列时(典型场景:daft.from_pydictSeries.from_pylist),还能从对象的具体值中提取类型信息,得到比纯类型推断更精确的 DataType。对应方法为DataType.infer_from_object——其实现是通过Series.from_pylist([obj])构造单元素 Series 再读取其datatype(),因此你可以用同一入口验证任意对象的推断结果。

在类型级映射的基础上,对象级推断有以下额外行为:

Python ObjectDaft Type
大于 2^63-1(Int64 最大值)的intUInt64
形如{ "k1": <T1>, "k2": <T2>, ... }dictStruct[k1: T1, k2: T2, ...]
小数点后 N 位的decimal.DecimalDecimal128[precision=38, scale=N]
元素类型为Tpandas.SeriesList[T]
元素类型为Tdaft.SeriesList[T]
带有 numpy dtypeTnumpy.ndarray/torch.Tensor/tensorflow.Tensor/jax.Array/cupy.ndarrayTensor[T]
单位为Unumpy.datetime64U= "Y"、"M"、"W"、"D" 时为 Date;U= "h"、"m"、"s" 时为 Timestamp[s];U= "ms" 时为 Timestamp[ms];U= "us" 时为 Timestamp[us];U= "ns"、"ps"、"fs"、"as" 时为 Timestamp[ns]
模式为MPIL.Image.Image(支持的模式:L、LA、RGB、RGBA)Image[M]

可以看到,对象级推断的核心价值在于利用运行时信息收紧类型dict的键值对能落成具体字段的 Struct 而非 Map,Decimal能定出 scale,datetime64能按单位精细区分 Date/Timestamp 及各精度,PIL 图像能保留具体通道模式。这与"Python 到 Daft"一节中dict只能推断为Map[K, V]PIL.Image.Image只能推断为Image[MIXED]形成了清晰对照——类型层面看不到键名和值范围,对象层面可以

实践建议

  1. 写 UDF 时优先声明类型注解@daft.func的返回类型注解会走infer_from_type路径,直接决定输出列的 DataType。给张量返回值使用jaxtyping或具名 torch Tensor 类型,可以获得带 dtype(甚至带 shape)的 Tensor 列,而不是宽泛的Tensor[Python]
  2. 需要精确类型时用cast显式声明:对象级推断无法覆盖的场景(如混合类型列表),应通过 [Expression.cast][daft.expressions.Expression.cast] 显式指定目标类型,而不是依赖推断。
  3. 取 Map 列值前先确认键唯一性:默认list[tuple[K, V]]是最安全的形式;只有确认数据干净或可接受覆盖语义时,再使用maps_as_pydicts="lossy"/"strict"换取 dict 便利性。
  4. 验证推断结果:怀疑某个注解/对象推断结果时,直接调用DataType.infer_from_type/DataType.infer_from_object打印结果即可,二者行为与转换管线保持一致。

参考

  • 类型转换规则原文档:docs/api/datatypes/type_conversions.md
  • Python 类型推断实现:daft/datatype.py(infer_from_type_infer_from_jaxtypinginfer_from_object
  • to_pylistmaps_as_pydicts:daft/series.py
  • Rust 侧字面量转 Python 的实现:src/daft-core/src/lit/python.rs

【免费下载链接】DaftHigh-performance data engine for AI and multimodal workloads. Process images, audio, video, and structured data at any scale项目地址: https://gitcode.com/GitHub_Trending/da/Daft

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 4:08:25

Windows笔记本电池循环计数与健康度:powercfg报告与换电池判断

1. 先搞清循环计数到底在数什么我见过太多人拿着笔记本电池报告截图来问&#xff1a;健康度才 78%&#xff0c;是不是该换电池了&#xff1f;结果一看循环计数&#xff0c;才 120 次。这两组数字如果在你的认知里是同一件事&#xff0c;后面的判断基本都会偏。Windows 笔记本电…

作者头像 李华
网站建设 2026/9/17 4:06:16

YOLO v11 针对 SAR 图像飞机检测的物理建模优化

简介&#xff1a;本资源是一套基于YOLO v11实现SAR图像飞机目标检测的完整开源项目&#xff0c;面向计算机视觉初学者、遥感图像处理研究者及AI工程实践者&#xff0c;解决合成孔径雷达图像中低对比度、弱纹理目标识别难的问题。压缩包共26个文件&#xff08;731KB&#xff09;…

作者头像 李华
网站建设 2026/9/17 4:05:32

Godot对象池实战:解决Node高频创建性能瓶颈

1. 为什么在 Godot 里非得搞个对象池&#xff1f;不是 new 一下就完事了&#xff1f;刚从 Unity 或 Java 转过来的朋友&#xff0c;看到“对象池”第一反应往往是&#xff1a;不就是反复创建销毁节点吗&#xff1f;Godot 又不是 C&#xff0c;GC 都替你扛着&#xff0c;还池个啥…

作者头像 李华
网站建设 2026/9/17 4:03:13

电商评论情感分析:构建可解释、可迭代的业务反馈闭环

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华