You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子类化Pandas Series重载运算符触发递归错误的排查请求

子类化Pandas Series并重载运算符触发递归错误的解决思路

问题复现

最小复现代码

import pandas as pd

class MySeries(pd.Series):
    def __mul__(self, other):
        print('hello!')
        return super().mul(other)

MySeries([1,2,3]) * 1

运行错误信息

hello!
...
hello!
  File "/home/jibi/.local/lib/python3.9/site-packages/pandas/core/ops/__init__.py", line 197, in flex_wrapper
    return op(self, other)
  File "<stdin>", line 4, in __mul__
...
  File "/home/jibi/.local/lib/python3.9/site-packages/pandas/core/ops/__init__.py", line 197, in flex_wrapper
    return op(self, other)
  File "<stdin>", line 4, in __mul__
packages/pandas/core/ops/common.py", line 90, in get_op_result_name
    if isinstance(right, (ABCSeries, ABCIndex)):
RecursionError: maximum recursion depth exceeded

观察到的现象

  • 添加mul方法无改善
  • 添加__rmul__方法无改善
  • 添加_constructor方法无改善(遵循官方子类化文档操作)
  • 仅与整数相乘时出错,与Series或子类实例相乘正常
  • 直接调用MySeries([1,2,3]).mul(1)也报错,移除__mul__方法则正常
  • 该问题同样出现在__add__、__sub__等其他运算符上
  • 子类化DataFrame并以相同方式重载__mul__时,*运算符可正常工作(仅Series子类存在此问题)

使用版本:pandas 1.4.3;python 3.9.5

解决思路

问题根源是Pandas的运算符分发机制:重载__mul__后,调用super().mul(other)时,Pandas内部的flex_wrapper会再次触发自定义的__mul__方法,形成递归循环。

可行解决方案

方案一:直接调用父类的__mul__方法

修改重载逻辑,跳过Pandas的mul包装方法,直接调用父类的运算符实现:

import pandas as pd

class MySeries(pd.Series):
    def __mul__(self, other):
        print('hello!')
        return super().__mul__(other)

MySeries([1,2,3]) * 1  # 正常运行,输出hello!并返回正确结果

方案二:使用底层算术方法避免递归

调用Pandas内部的_arith_method直接执行运算,绕开运算符包装的递归触发:

import pandas as pd
import operator
from pandas.core.ops import _arith_method

class MySeries(pd.Series):
    def __mul__(self, other):
        print('hello!')
        return _arith_method(self, other, operator.mul, 'mul')

方案三:结合构造器确保返回子类实例

正确实现_constructor方法,让运算结果返回MySeries实例,同时避免递归:

import pandas as pd

class MySeries(pd.Series):
    def _constructor(self, values, index=None, dtype=None, name=None, fastpath=False):
        return MySeries(values, index=index, dtype=dtype, name=name)
    
    def __mul__(self, other):
        print('hello!')
        result = super().__mul__(other)
        return self._constructor(result)

核心原因:Pandas的mul实例方法会通过内部的运算符分发逻辑再次调用自定义的__mul__,而直接调用super().__mul__会跳过这个包装流程,执行原始的Series乘法运算,从而终止递归循环。

内容的提问来源于stack exchange,提问作者user2655730

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 15:45:42