如何在Python中可靠获取当前类方法的模块与类信息(支持继承、动态创建)
解决类方法继承/元类场景下定义模块与类的识别问题
Python中类方法通过cls参数绑定调用它的类,这导致在继承或元类创建的类中,直接通过cls.__module__和cls.__name__只能拿到调用时的类信息,而非方法实际定义的类和模块。要解决这个问题,可以通过自定义装饰器在方法定义阶段就捕获并存储原始定义信息。
核心方案:定义跟踪装饰器
编写一个装饰器,在方法定义时记录它的原始模块和所属类,后续调用时直接读取这些预存的信息即可,不受继承层级或元类影响:
def track_definition(func): # 记录方法定义所在的模块 func._defined_module = func.__module__ # 处理类方法:类方法的原始函数存储在__func__属性中 if isinstance(func, classmethod): original_func = func.__func__ # 通过__qualname__拆分出所属类名(格式为"ClassName.MethodName") qualname_parts = original_func.__qualname__.split('.') func._defined_class = qualname_parts[-2] # 可扩展支持静态方法、实例方法等 elif isinstance(func, staticmethod): original_func = func.__func__ qualname_parts = original_func.__qualname__.split('.') func._defined_class = qualname_parts[-2] if len(qualname_parts) >=2 else None else: qualname_parts = func.__qualname__.split('.') func._defined_class = qualname_parts[-2] if len(qualname_parts) >=2 else None return func
基础继承场景测试
将装饰器应用到类方法上,即可在调用时区分调用类和定义类:
class BaseClass: @track_definition @classmethod def mymethod(cls): print(f"调用类: {cls.__module__}.{cls.__name__}") print(f"定义类: {mymethod._defined_module}.{mymethod._defined_class}") class DerivedClass(BaseClass): pass DerivedClass.mymethod()
输出结果:
调用类: __main__.DerivedClass 定义类: __main__.BaseClass
元类场景适配
如果类是通过元类创建的,只需在元类的__new__方法中自动为方法添加装饰器,即可同样生效:
class Meta(type): def __new__(cls, name, bases, attrs): # 遍历类属性,为可调用对象添加定义跟踪装饰器 for attr_name, attr_value in attrs.items(): if callable(attr_value) or isinstance(attr_value, (classmethod, staticmethod)): attrs[attr_name] = track_definition(attr_value) return super().__new__(cls, name, bases, attrs) class BaseMetaClass(metaclass=Meta): @classmethod def meta_method(cls): print(f"调用类: {cls.__module__}.{cls.__name__}") print(f"定义类: {meta_method._defined_module}.{meta_method._defined_class}") class DerivedMeta(BaseMetaClass): pass DerivedMeta.meta_method()
输出结果:
调用类: __main__.DerivedMeta 定义类: __main__.BaseMetaClass
原理说明
__module__属性:在方法定义时就固定指向定义该方法的模块,不会随继承改变。__qualname__属性:记录方法的完整限定名称(包含所属类),通过拆分该字符串可以准确获取方法定义时的所属类。- 装饰器在方法定义阶段执行,将这些信息存储为自定义属性(如
_defined_module、_defined_class),后续调用时直接读取即可,完全不受调用时的类绑定影响。
内容的提问来源于stack exchange,提问作者Aryan Pro
相关产品推荐
相关产品推荐

