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

运行时覆写Test类print方法:首次抛异常后续正常(不可改原类)

运行时改写Test类print方法实现首次抛异常的解决方案

你写的代码出现无限递归的原因很直白:你把test_class的print方法替换成了raise_exception函数,而copy_test其实是test_class的引用,所以当你在raise_exception里调用copy_test.print()时,本质还是在调用raise_exception自己,这不就无限循环了嘛。

正确的思路是提前保存原始的print方法,而不是保存对象引用。因为对象的方法被替换后,再调用对象的print会指向新函数,但提前存好的原方法依然指向最初的实现。

修正后的代码

class Test:
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def print(self):
        print(f"a-> {self.a}, and b-> {self.b}")

# 实例化对象
test_instance = Test(1,2)
# 先保存原始的print方法,这是关键
original_print = test_instance.print
test_instance.num_raise = 0

def wrapped_print():
    if test_instance.num_raise == 0:
        test_instance.num_raise += 1
        raise Exception("save_clusters method exception")
    else:
        # 直接调用保存的原始方法,不会触发递归
        return original_print()

# 替换实例的print方法
test_instance.print = wrapped_print

try:
    test_instance.print()  # 首次调用:抛出异常
except Exception as e:
    print(f"捕获异常: {e}")
    test_instance.print()  # 第二次调用:正常执行
test_instance.print()  # 后续调用:均正常执行

更优雅的闭包版本(无需给实例加额外属性)

如果不想给实例添加num_raise这种额外属性,可以用闭包封装计数逻辑:

test_instance = Test(1,2)
original_print = test_instance.print

def wrap_print():
    call_count = 0
    def inner():
        nonlocal call_count
        if call_count == 0:
            call_count += 1
            raise Exception("save_clusters method exception")
        else:
            return original_print()
    return inner

test_instance.print = wrap_print()

try:
    test_instance.print()
except Exception as e:
    print(f"捕获异常: {e}")
    test_instance.print()
test_instance.print()

这两个版本都能满足需求:首次调用抛异常,之后每次调用都执行原本的print逻辑,同时避开了mock、深拷贝,也不需要修改Test类的代码。

内容的提问来源于stack exchange,提问作者An old man in the sea.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:03:32