Python装饰器包装实例方法未传入self参数报错解决方案
问题根源
原有实现的核心问题是使用functools.partial包装内层参数处理函数后,返回的partial对象不支持Python实例方法的描述符自动绑定规则:
- 类中定义的普通函数作为实例方法调用时,会自动将当前实例作为第一个
self参数传入 - partial对象不会触发这个自动绑定流程,直接导致参数位置错位
你看到的第一次调用"正常运行"其实是假象:传入的第一个位置参数1被错当成了self,所以打印的位置参数只有(2,);第二次无参调用时没有多余位置参数填充self位,直接抛出参数缺失错误。
修复代码
移除多余的partial包装,让装饰器返回普通的包装函数,保留实例方法默认的参数绑定逻辑即可,完整可运行代码如下:
import traceback from threading import Thread def backgroundThread(name=''): def fnWrapper(decorated_func): def argsWrapper(*inner_args, **inner_kwargs): def exceptionWrapper(fn, *args, **kwargs): try: fn(*args, **kwargs) except Exception: traceback.print_exc() thread_name = name if name else decorated_func.__name__ th = Thread( name=thread_name, target=exceptionWrapper, args=(decorated_func, *inner_args), kwargs=inner_kwargs ) th.start() # 同步原函数元信息,方便调试 argsWrapper.__name__ = decorated_func.__name__ argsWrapper.__doc__ = decorated_func.__doc__ return argsWrapper return fnWrapper class X: @backgroundThread() def myfun(self, *args, **kwargs): print(args, kwargs) print("myfun was called") x = X() x.myfun(1, 2, foo="bar") x.myfun()
运行效果
修复后两次调用都会正确绑定self参数:
- 第一次调用输出
(1, 2) {'foo': 'bar'}和myfun was called,参数位置完全正确 - 第二次无参调用不会报self缺失,输出
() {}和myfun was called - 方法内抛出的异常会被捕获并打印完整栈信息,不会导致线程静默退出
补充注意:异常捕获建议明确指定捕获
Exception类型,不要使用空except,避免误拦截系统级退出、键盘中断等不该被业务逻辑捕获的异常。
内容的提问来源于stack exchange,提问作者MafMal
相关产品推荐
相关产品推荐

