无法获取带@staticmethod装饰器的调用类方法所属类名
问题:静态方法调用场景下无法获取调用类名的解决思路
之前参考相关方法实现函数内获取调用类名时,遇到了静态方法的特殊问题:stack[1].frame.f_locals["self"].__class__.__name__ 在实例方法调用场景下可以正常获取类名,但在带@staticmethod装饰器的类方法中调用时,会抛出KeyError: 'self'错误。
示例代码如下,实例方法调用some_func可正常运行,但静态方法调用会报错:
def some_func(): '... some_code ...' import inspect stack = [x for x in inspect.stack() if 'My_Module' in str(x)] try: src = '<{}>.'.format(stack[1].frame.f_locals["self"].__class__.__name__) except: from traceback import format_exc print(format_exc()) src = '' '... some_code ...' class SomeClass: @staticmethod def tester(): some_func()
请问有什么解决思路?
解决思路
1. 区分调用场景,兼容静态方法与实例方法
静态方法本身没有self参数,所以不能直接从f_locals中取self。可以通过检查调用栈的代码上下文,结合函数的__qualname__来获取类名——Python中函数的__qualname__会包含完整的类层级路径,格式为类名.方法名。
修改后的some_func示例:
def some_func(): '... some_code ...' import inspect src = '' # 获取调用栈,跳过当前函数本身 stack = inspect.stack() if len(stack) >= 2: caller_frame = stack[1].frame caller_code = caller_frame.f_code # 实例方法场景:从f_locals取self获取类名 if 'self' in caller_frame.f_locals: cls_name = caller_frame.f_locals['self'].__class__.__name__ src = f'<{cls_name}>' else: # 静态方法场景:解析__qualname__获取类名 qualname = caller_code.co_qualname if '.' in qualname: cls_name = qualname.split('.')[0] src = f'<{cls_name}>' '... some_code ...'
2. 结合模块验证提升可靠性
如果担心__qualname__解析出错(比如嵌套类、复杂方法命名),可以结合inspect.getmodule从调用模块中验证类是否存在:
def some_func(): '... some_code ...' import inspect src = '' stack = inspect.stack() if len(stack) >= 2: caller_frame = stack[1].frame caller_code = caller_frame.f_code caller_module = inspect.getmodule(caller_frame) if 'self' in caller_frame.f_locals: cls_name = caller_frame.f_locals['self'].__class__.__name__ src = f'<{cls_name}>' else: qualname_parts = caller_code.co_qualname.split('.') if len(qualname_parts) >= 2: cls_name = qualname_parts[0] # 验证模块中是否存在该类,避免解析错误 if hasattr(caller_module, cls_name): src = f'<{cls_name}>' '... some_code ...'
3. 显式传递类名的替代方案
如果依赖调用栈的实现存在兼容性风险(比如Python版本差异、多层装饰器干扰),最直接的方式是调用时显式传递类名:
def some_func(caller_cls_name=''): '... some_code ...' src = f'<{caller_cls_name}>' if caller_cls_name else '' '... some_code ...' class SomeClass: @staticmethod def tester(): some_func(caller_cls_name=SomeClass.__name__)
内容的提问来源于stack exchange,提问作者Ulysses
相关产品推荐
相关产品推荐

