类内装饰器调用报错:如何在MetabaseManager类中正确使用私有装饰器?
解决类内私有装饰器装饰方法时的
staticmethod不可调用错误 错误原因
你遇到的TypeError: 'staticmethod' object is not callable核心问题是装饰器应用顺序错误:如果将@staticmethod放在私有装饰器@_renewSessionIfExpired上方,装饰器会接收staticmethod对象而非原始函数——而staticmethod本身的调用逻辑不符合装饰器的预期,因此触发报错。
另外需要注意:staticmethod无法访问实例或类的属性,根本没法检查会话状态,因此需要访问会话的方法不应该用staticmethod,应改用实例方法或类方法。
正确实现方案
方案1:装饰实例方法(推荐,会话状态绑定到实例)
将getQuestion定义为实例方法,私有装饰器直接修饰原始方法,包装函数通过self访问实例的会话状态。
import time class MetabaseManager: def __init__(self): self.session_token = None self.session_expires_at = 0 def _renewSessionIfExpired(func): def wrapper(self, *args, **kwargs): # 检查会话是否过期 if not self.session_token or time.time() > self.session_expires_at: # 调用Metabase API续期会话 self.session_token = self._fetch_new_session() self.session_expires_at = time.time() + 3600 # 设为1小时有效期 return func(self, *args, **kwargs) return wrapper def _fetch_new_session(self): # 模拟获取新会话的API调用 return f"instance_token_{int(time.time())}" @_renewSessionIfExpired def getQuestion(self, question_id): # 实际调用Metabase API获取问题 return { "question_id": question_id, "used_token": self.session_token, "content": "Metabase question content" }
方案2:装饰类方法(会话状态全局共享)
如果所有实例共享同一会话,可以使用类方法,注意装饰顺序:先应用私有装饰器,再用@classmethod修饰。
import time class MetabaseManager: _session_token = None _session_expires_at = 0 def _renewSessionIfExpired(func): def wrapper(cls, *args, **kwargs): if not cls._session_token or time.time() > cls._session_expires_at: cls._session_token = cls._fetch_new_session() cls._session_expires_at = time.time() + 3600 return func(cls, *args, **kwargs) return wrapper @classmethod def _fetch_new_session(cls): return f"class_token_{int(time.time())}" @classmethod @_renewSessionIfExpired def getQuestion(cls, question_id): return { "question_id": question_id, "used_token": cls._session_token, "content": "Shared Metabase question content" }
关键注意事项
- 装饰顺序优先级:使用
@classmethod时,必须将私有装饰器放在下方,确保装饰器先处理原始函数,再转换为类方法。 - 方法类型适配:需要访问会话状态的方法禁止使用
staticmethod,否则无法读取/更新会话信息。 - Python 3.6兼容性:上述代码完全兼容Python 3.6,嵌套函数形式的装饰器在该版本中可正常运行。
内容的提问来源于stack exchange,提问作者Amir Shabani
相关产品推荐
相关产品推荐

