Pylint对类内定义的装饰器报not-callable错误是否为误报及优化方案
报错原因说明
这个报错不属于Pylint误报,根源是装饰器的定义方式不符合Python类成员的语义规范:
with_timeout被定义为普通类成员方法,Pylint静态检查会默认它的第一个入参是类实例self- 你在类定义阶段用
@with_timeout装饰do_something时,实际传入的参数是未绑定的函数对象,和Pylint预期的实例类型不匹配,因此触发f is not callable的错误提示 - 代码能正常运行是因为Python在类定义阶段调用装饰器时,不会将其作为实例方法处理,直接把被装饰函数作为参数传入,所以执行逻辑符合预期。
更优实现方案
优化点说明:
- 推荐将装饰器移出类定义,避免类成员方法的语义冲突
- 补充缺失的
datetime、functools.wraps依赖导入 - 用
total_seconds()代替seconds计算耗时,避免跨天场景下的计算错误 - 可选增加剩余时长耗尽的异常抛出逻辑,符合超时控制的场景需求
优化后代码示例:
from datetime import datetime from functools import wraps # 装饰器移到类外定义 def with_timeout(f): @wraps(f) def wrapper(self, *args, **kwargs): start = datetime.now() result = f(self, *args, **kwargs) # 计算方法执行耗时 time_cost = (datetime.now() - start).total_seconds() # 剩余时长最低保留为非负数 self.time_remaining = max(0, self.time_remaining - time_cost) # 可选:剩余时长耗尽时抛出超时异常 if self.time_remaining <= 0: raise TimeoutError("Remaining time exhausted") return result return wrapper class TestClass: def __init__(self): self.time_remaining = 240 @with_timeout def do_something(self, param): # 此处编写业务逻辑 pass
如果你希望保留装饰器在类内部定义,只需要给with_timeout加上@staticmethod装饰器即可修复Pylint报错:
from datetime import datetime from functools import wraps class TestClass: def __init__(self): self.time_remaining = 240 @staticmethod def time_taken(start): return (datetime.now() - start).total_seconds() @staticmethod def with_timeout(f): @wraps(f) def wrapper(self, *args, **kwargs): start = datetime.now() result = f(self, *args, **kwargs) self.time_remaining = max(0, self.time_remaining - TestClass.time_taken(start)) return result return wrapper @with_timeout def do_something(self, param): # 此处编写业务逻辑 pass
内容的提问来源于stack exchange,提问作者user3001471
相关产品推荐
相关产品推荐

