Polars自定义命名空间注册后如何规避mypy/pyright类型错误?
问题
在使用Polars注册自定义命名空间函数时,mypy或pyright会持续抛出类型错误,除了每次调用时添加# type: ignore[attr-defined]注解,有没有其他方法规避这些类型检查器错误?
以下是示例代码(文件checker.py):
import polars as pl @pl.api.register_expr_namespace("greetings") class Greetings: def __init__(self, expr: pl.Expr): self._expr = expr def hello(self) -> pl.Expr: return (pl.lit("Hello ") + self._expr).alias("hi there") def goodbye(self) -> pl.Expr: return (pl.lit("Sayōnara ") + self._expr).alias("bye") print(pl.DataFrame(data=["world", "world!", "world!!"]).select( [ pl.all().greetings.hello(), # type: ignore[attr-defined] pl.all().greetings.goodbye(), ] ))
执行mypy检查的输出:
% mypy checker.py checker.py:19: error: "Expr" has no attribute "greetings" [attr-defined] Found 1 error in 1 file (checked 1 source file) % mypy --version mypy 1.8.0 (compiled: yes)
执行pyright检查的输出:
% pyright checker.py /path/to/checker.py /path/to/checker.py:19:18 - error: Cannot access member "greetings" for type "Expr" Member "greetings" is unknown (reportGeneralTypeIssues) 1 error, 0 warnings, 0 informations % pyright --version pyright 1.1.343
解决方案
方法1:添加类型扩展Stub文件
给Polars的Expr类型补充自定义命名空间的类型注解,创建一个.pyi格式的Stub文件(比如polars_ext.pyi):
import polars as pl class Greetings: def __init__(self, expr: pl.Expr) -> None: ... def hello(self) -> pl.Expr: ... def goodbye(self) -> pl.Expr: ... class Expr(pl.Expr): greetings: Greetings
然后在主代码顶部引入该扩展类型(仅用于类型检查):
from polars_ext import Expr # type: ignore[import]
也可以在mypy.ini或pyrightconfig.json中配置Stub文件路径,让类型检查器自动识别扩展。
方法2:使用类型断言
定义包含自定义命名空间的类型,调用前将表达式断言为该类型:
from typing import cast class ExprWithGreetings(pl.Expr): greetings: Greetings # 调用时 expr = cast(ExprWithGreetings, pl.all()) expr.greetings.hello()
方法3:针对性修改类型检查器配置
在配置文件中对特定文件或规则禁用相关检查,避免全局影响:
- mypy:在
mypy.ini中添加[mypy-checker] # 仅禁用attr-defined错误 disable_error_codes = attr-defined - pyright:在
pyrightconfig.json中添加{ "reportGeneralTypeIssues": false }
注意:此方法会放宽类型检查精度,建议仅在目标文件/模块中启用。
方法4:封装为普通函数
将自定义命名空间的调用封装成普通函数,仅在封装内部添加一次忽略注解:
def greetings_hello(expr: pl.Expr) -> pl.Expr: return expr.greetings.hello() # type: ignore[attr-defined] def greetings_goodbye(expr: pl.Expr) -> pl.Expr: return expr.greetings.goodbye() # type: ignore[attr-defined] # 调用时无需再加注解 print(pl.DataFrame(data=["world", "world!", "world!!"]).select( [ greetings_hello(pl.all()), greetings_goodbye(pl.all()), ] ))
内容的提问来源于stack exchange,提问作者lisonator
相关产品推荐
相关产品推荐

