
Polars 的 with_columns 不支持在同一次调用中先定义再引用新列(如 AB → ABC),但可通过表达式变量复用或海象运算符(:=)实现链式计算,且底层查询优化确保表达式仅执行一次。
polars 的 `with_columns` 不支持在同一次调用中先定义再引用新列(如 ab → abc),但可通过表达式变量复用或海象运算符(`:=`)实现链式计算,且底层查询优化确保表达式仅执行一次。
在 Polars 中,with_columns(以及 select、filter、group_by 等上下文)内所有表达式是并行评估的——这意味着你无法在同一个 with_columns 调用中,先用 (pl.col("A") + pl.col("B")).alias("AB") 创建列 "AB",再立即用 pl.col("AB") 作为后续表达式的输入(例如 (pl.col("AB") + pl.col("C")).alias("ABC"))。该写法会报错:Column not found: AB,因为 "AB" 在当前上下文中尚未“落地”,仅是一个待计算的表达式节点,而非已存在的列。
✅ 正确做法是:将中间表达式提取为 Python 变量,然后在多个列定义中复用它:
import polars as pl
df = pl.DataFrame({
"a": [1, 4],
"b": [2, 5],
"c": [3, 6],
})
ab_expr = pl.col("a") + pl.col("b")
result = df.with_columns(
ab_expr.alias("ab"),
(ab_expr + pl.col("c")).alias("abc"),
)
print(result)
输出:
shape: (2, 5) ┌─────┬─────┬─────┬─────┬─────┐ │ a ┆ b ┆ c ┆ ab ┆ abc │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ i64 ┆ i64 ┆ i64 │ ╞═════╪═════╪═════╪═════╪═════╡ │ 1 ┆ 2 ┆ 3 ┆ 3 ┆ 6 │ │ 4 ┆ 5 ┆ 6 ┆ 9 ┆ 15 │ └─────┴─────┴─────┴─────┴─────┘
⚠️ 注意事项:
- 表达式复用不会导致重复计算:Polars 的查询优化器会自动识别共享子表达式(如
ab_expr),将其编译为一个公共计算节点(内部标记为__POLARS_CSER_...),并在执行计划中只计算一次。 - 可通过
.lazy().explain()验证优化效果,输出中可见嵌套的WITH_COLUMNS结构,明确体现子表达式提升(sub-plan lifting)。 - 若追求代码紧凑性,可使用 海象运算符(
:=) 在表达式内部完成赋值与复用(需 Python ≥ 3.8):
result = df.with_columns(
(ab_expr := pl.col("a") + pl.col("b")).alias("ab"),
(ab_expr + pl.col("c")).alias("abc"),
)
该写法语义等价,但更内聚;不过需注意其可读性对团队成员的影响,建议在复杂逻辑中优先选用显式变量声明方式。
总结:Polars 的列创建是声明式、惰性且优化驱动的。避免“列依赖幻觉”,拥抱表达式复用——这是写出高效、清晰 Polars 代码的关键习惯。










