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

如何修复UserString替换builtins.str引发的RecursionError问题

递归错误原因

原代码触发RecursionError的核心逻辑是:UserString内部实现会依赖全局命名空间的str类型做数据转换、实例初始化操作。你把builtins.str替换为自定义的String子类后,每次创建String实例,UserString的内部逻辑就会再次调用被替换后的str(也就是String自身)创建新实例,无限循环嵌套最终触发栈溢出。

修复方案

方案1:不替换内置str,单独使用自定义字符串类(推荐)

直接替换内置类型属于高风险的猴子补丁操作,很容易和标准库、第三方依赖的逻辑产生兼容问题,绝大多数场景下直接使用自定义子类即可满足需求,不会触发递归:

import unicodedata
from collections import UserString


class CustomStr(UserString):
    def isnumber(self):
        # 校验是否为合法浮点格式字符串
        try:
            float(self.data)
            return True
        except ValueError:
            pass
        # 校验是否为Unicode定义的数值类字符
        try:
            unicodedata.numeric(self.data)
            return True
        except (TypeError, ValueError):
            pass
        return False


# 需要使用带isnumber方法的字符串时,手动实例化CustomStr即可
print(CustomStr('0').isnumber())  # True
print(CustomStr('1').isnumber())  # True
print(CustomStr('-1').isnumber())  # True
print(CustomStr('0.1').isnumber())  # True
print(CustomStr('a1').isnumber())  # False

方案2:直接给原生str类动态绑定方法(适配字面量直接调用的需求)

如果你一定要实现所有原生字符串、字符串字面量都能直接调用isnumber()的效果,不要通过替换builtins.str的方式实现,可以直接给原生str类动态绑定方法,全程不会修改str的引用,自然不会触发递归:

import ctypes
import unicodedata


def isnumber(self):
    try:
        float(self)
        return True
    except ValueError:
        pass
    try:
        unicodedata.numeric(self)
        return True
    except (TypeError, ValueError):
        pass
    return False


# 绕过Python的内置类属性修改限制,动态给str绑定方法
class PyObject(ctypes.Structure):
    _fields_ = [("ob_refcnt", ctypes.c_ssize_t), ("ob_type", ctypes.c_void_p)]


def get_class_dict(cls):
    if hasattr(cls, '__dictoffset__') and cls.__dictoffset__:
        addr = id(cls) + cls.__dictoffset__
        return ctypes.cast(addr, ctypes.POINTER(ctypes.py_object))[0]
    return cls.__dict__

str_class_dict = get_class_dict(str)
str_class_dict['isnumber'] = isnumber


# 测试:原生字符串、字面量都可以直接调用
print('0'.isnumber())  # True
print('-1'.isnumber())  # True
print('0.1'.isnumber())  # True
print('a1'.isnumber())  # False
print(str(123).isnumber())  # True

注意:直接修改内置类的方法属于侵入式操作,仅适合在完全可控的个人脚本环境中使用,不要在通用库、线上生产环境中使用,避免引发不可预知的兼容问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:54:28