Polars 2.0 预发布
By on Wed, 2 Sept 2026
今天我们发布 Polars 2.0 的第一个候选版本(RC),正式版将在随后几周推出。我们并不打算让 Polars 2.0 成为一个大功能更新;事实上,我们希望它对你来说是个"无聊"的体验。此次升大版本号,是因为我们可以摆脱过去一些制约发展的设计决策,并将默认值调整为更合理、惠及更多用户的设置。最大的默认变更是:所有 LazyFrame 查询现在都将运行在流式引擎上,普通用户因此可以期待内存占用和性能的大幅改善。总体来看,我们预期流式引擎可以轻松实现 5 倍加速。
为帮助迁移至 2.0,我们已发布完整的 迁移指南,本文将介绍其中几个重点。
流式引擎成为默认
这是 2.0 最具影响力的变更:对 LazyFrame 调用 collect 现在默认使用流式引擎,为大多数查询带来显著的内存和性能提升。之所以需要升大版本,是因为流式引擎对于某些操作(如 join、group_by、unpivot 等)默认不保证行顺序。若需要保证这些操作的行顺序,可通过设置 maintain_order=True 来启用。
希望继续使用"内存中"引擎作为默认值的用户,也可以通过设置引擎亲和性来实现。
```python lf = pl.LazyFrame({"k": [2, 1, 0], "v": ["a", "b", "c"]}) other = pl.LazyFrame({"k": [0, 1, 2], "r": ["x", "y", "z"]}) # 2.0: engine="auto" 现在默认使用流式引擎。 # join、group_by、unpivot 等操作不再保证行顺序。 ( lf .join(other, on="k", how="left") .collect() ) # ┌─────┬─────┬─────┐ # │ k ┆ v ┆ r │ <- 顺序可能与其 `lf` 原始行顺序不同 # └─────┴─────┴─────┘ # 为该查询开启可观测的顺序: ( lf .join(other, on="k", how="left", maintain_order="left") .collect() ) # 或者将旧的内存引擎设为进程级默认值: pl.Config.set_engine_affinity("in-memory") # ...或在单次查询中指定: ( lf .join(other, on="k", how="left") .collect(engine="in-memory") ) ```更严格的 Polars
Polars 追求严格与快速失败。错误最好能在调用初期就立即抛出,而不是在流水线运行 20 分钟之后才报错。针对数据类型不匹配的隐式行为应当作为可选选项,而不应作为默认行为——因为这类不匹配往往会隐藏 bug。随着 AI 驱动开发的兴起,这种严格性变得尤为重要。智能体可以通过调用 collect_schema() 提前验证查询结构,该方法无需物化任何数据即可解析类型并捕获模式层面的不匹配。这能为智能体提供快速的反馈,使其能够更快地迭代。并非所有错误都能在查询计划编译阶段被捕获——有些错误依赖于实际数据。在这些情况下,Polars 默认采用更严格的行为,确保不一致之处能被及时发现,而非静默地产生错误结果。
以下是 Polars 变得更加严格的一些示例:
is_in 无损类型强制转换
当你在不同类型的数据上执行 is_in 表达式时,Polars 过去会将两种类型都强制转换为它们共同的父类型,即使该转换会造成精度丢失。
下面是一个用户 ID 因静默的类型不匹配而出错的示例。
# 检查用户 ID 是否在“被标记”的账号列表内
# (flagged_ids 从 JSON 导出文件中加载,其中大数值 ID 已变为浮点数)
flagged_ids = pl.Series([9007199254740992.0])
user_id = pl.Series([9007199254740993]) # Int64 -> 相差 1 的不同 ID
user_id.is_in(flagged_ids)
在 2.0 之前,user_id 会被强制转换为 Float64 以匹配 flagged_ids。但 9007199254740993 超过了 2^53(9007199254740992)——即 float64 能精确表示的最大整数——因此它会静默地舍入为 9007199254740992.0,产生误报。
2.0 中会抛出:InvalidOperationError: 'is_in' cannot check for Int64 values in List(Float64) data.,用户需要显式转换来处理有损类型转换。
严格拼接
水平拼接现在会检查长度,而非静默填充 null。
# 将每日交易数与每日欺诈标记数拼接
transactions = pl.DataFrame({"day": [1, 2, 3, 4, 5], "count": [120, 98, 143, 87, 156]})
# 上游任务对 day 5 静默失败
fraud_flags = pl.DataFrame({"flagged": [2, 0, 5, 1]}) # 只有 4 行
pl.concat([transactions, fraud_flags], how="horizontal")
shape: (5, 2)
┌─────┬───────┬─────────┐
│ day ┆ count ┆ flagged │
│ 1 ┆ 120 ┆ 2 │
│ 2 ┆ 98 ┆ 0 │
│ 3 ┆ 143 ┆ 5 │
│ 4 ┆ 87 ┆ 1 │
│ 5 ┆ 156 ┆ null │ <- day 5 静默缺失标记计数
└─────┴───────┴─────────┘
在 2.0 中会抛出:
ShapeError: cannot concat dataframes with different heights in 'strict' mode
如果你确实需要填充,必须显式选择 how="horizontal_extend",让读者明确你的意图。
移除 cast,改用专用方法/构造函数
另一项值得关注的改动是移除了许多模糊的 cast,统一改为通过专用解析表达式来操作,让数据解析方式只有一种正确路径。
Enums/Categoricals 与整数互转
pl.Series([None, 1, 0, 2], dtype=pl.UInt32).cast(pl.Enum(["a", "b", "c"]))
# ComputeError: casting from u32 to enum is not supported.
应改用:.cat.to(dtype) 用于 int → categorical,.cat.physical() 用于 categorical → int。
解析字符串到时间类型
pl.Series(["2022-08-30"]).cast(pl.Date)
# InvalidOperationError: casting from string to date is not supported.
应改用 .str.to_date() / .str.to_datetime()。它们支持指定解析格式,让你对数据如何解析拥有更多控制。
以上仅是部分示例,我们还做了大量严格性改进。详见迁移指南。
提供更有用的错误信息
我们投入大量精力确保用户或你的代理在使用已被废弃的旧参数时仍能继续工作。为此新增了两个类型化异常:polars.exceptions.AttributeRemovedError 和 polars.exceptions.ArgumentRemovedError,分别处理已移除的属性/方法和已移除的参数。
错误信息会引导你使用新的 API。下面展示两个示例。
>>> lf.melt(id_vars="a", value_vars="b")
polars.exceptions.AttributeRemovedError: `melt` was removed in version 2.0;
use `LazyFrame.unpivot` instead, with `index` instead of `id_vars`
and `on` instead of `value_vars`
>>> df.join(df, on="a", join_nulls=True)
polars.exceptions.ArgumentRemovedError: the argument 'join_nulls' for
'DataFrame.join' was deprecated in version 1.24 and has been removed
in 2.0.0. It was renamed to 'nulls_equal' in version 2.0.
大多数被移除的功能早已标记为废弃,如果你一直保持更新,应该不会影响你的流水线。如果你认为我们应该保留某些你依赖的功能,请与我们联系。
最后的话
Polars 2.0 专注于更好的默认值(最重要的是流式引擎)和更优化的 API。我们希望这次发布足够"平淡"——意味着没有太多需要大改的内容。我们不会将新功能隐藏在重大版本升级之后,一旦准备好就会立即发布。
但别误会,Polars 2.x 会比 1.x 强很多。还有很多正在进行中的工作我们尚未充分公开:流式引擎的原生外存支持、全新的 IO 插件设计、我们预期会成为最快的 S3 读取器、SQL 覆盖的大幅改进、基于成本的优化器、连接重排序,以及 mmap 的移除——这将让流水线实现端到端的完全异步。
通过安装 pip install polars==2.0rc1 来试用候选版本。试试手,然后在这里联系我们:https://github.com/pola-rs/polars/issues 或在 Discord 上联系:https://discord.gg/4UfP5cfBE7。