Polars自定义表达式扩展问题:参数传递与调用逻辑异常排查
解决方案
问题分析
你的代码存在两个核心问题:
__init__方法不能返回表达式,它的作用仅为初始化类实例、保存传入的表达式和参数,返回非None值会破坏Python类的初始化逻辑,导致参数绑定异常。- 未遵循Polars表达式扩展的规范逻辑,需要让自定义命名空间的调用直接返回合法的Polars表达式。
正确实现代码(推荐方式)
import polars as pl @pl.api.register_expr_namespace("EWSD") class ExponentialMovingStd: def __init__(self, expr: pl.Expr): # __init__仅绑定目标表达式,不处理参数 self._expr = expr def __call__( self, *, alpha: float | None = None, span: int | None = None, half_life: int | None = None, **ewm_std_kwargs, ) -> pl.Expr: # 在__call__方法中接收参数并执行计算逻辑 return ( self._expr.ewm_std( alpha=alpha, span=span, half_life=half_life, **ewm_std_kwargs ) .cast(pl.UInt8) )
调用方式
df.with_columns( pl.col("var").EWSD(span=21).alias("21span_var") )
另一种实现(初始化时直接传参)
如果希望参数直接在命名空间初始化时传入,可通过实现__polars_expr__方法让Polars自动将类实例识别为表达式:
import polars as pl @pl.api.register_expr_namespace("EWSD") class ExponentialMovingStd: def __init__( self, expr: pl.Expr, *, alpha: float | None = None, span: int | None = None, half_life: int | None = None, **ewm_std_kwargs, ): self._expr = expr self.alpha = alpha self.span = span self.half_life = half_life self.ewm_std_kwargs = ewm_std_kwargs def __polars_expr__(self) -> pl.Expr: # 实现该方法,让Polars将实例视为合法表达式 return ( self._expr.ewm_std( alpha=self.alpha, span=self.span, half_life=self.half_life, **self.ewm_std_kwargs ) .cast(pl.UInt8) )
关键说明
- 第一种方式更贴合Polars官方扩展的设计模式:命名空间类初始化仅绑定表达式,通过类方法(此处用
__call__)接收参数并返回结果。 - 第二种方式通过
__polars_expr__方法满足「无需额外调用即可获取结果」的需求,同时保证参数能被正确绑定。 - 两种实现都能解决你之前遇到的
span参数为None的问题。
内容的提问来源于stack exchange,提问作者Kevin Li
相关产品推荐
相关产品推荐

