如何区分Python中的外部函数、各类方法及Setter/Getter?
如何区分Python中的外部函数、静态方法、类方法、实例方法、Getter和Setter
在编写装饰器做参数类型校验时,用type()无法精准区分实例方法、Getter/Setter等类型——比如接收self的Getter和Setter会被识别为function而非实例方法,导致没法正确跳过self参数的类型校验。下面给出准确区分各类函数/方法的方案,以及适配参数校验的实现。
核心思路:用inspect模块替代type()判断
Python的函数与方法绑定机制导致type()无法精准区分类型,inspect模块提供了专门的类型检查工具,结合函数的__qualname__和所属类的属性,就能准确识别所有目标类型。
实现类型判断函数
下面的get_func_type函数可以返回当前函数/方法的具体类型:
import inspect def get_func_type(func): # 判断是否是绑定方法(实例方法/类方法) if inspect.ismethod(func): # 类方法的__self__是类本身(type实例),实例方法的__self__是类实例 return "类方法" if isinstance(func.__self__, type) else "实例方法" # 判断是否是函数对象 elif inspect.isfunction(func): # 通过__qualname__判断是否属于某个类 qualname_parts = func.__qualname__.split('.') if len(qualname_parts) >= 2: class_name = qualname_parts[-2] module = inspect.getmodule(func) cls = getattr(module, class_name, None) if cls: # 获取类中对应名称的属性 class_attr = getattr(cls, func.__name__, None) # 判断是否是静态方法 if isinstance(class_attr, staticmethod): return "静态方法" # 判断是否是property的Getter/Setter elif isinstance(class_attr, property): if class_attr.fget is func: return "Getter方法" elif class_attr.fset is func: return "Setter方法" # 类中未绑定的实例函数 return "实例函数(未绑定)" # 不属于任何类的外部函数 return "外部函数" # 其他未知类型 return "未知类型"
验证类型判断
把你测试代码中的show_type替换成上述函数,执行后能得到准确的类型结果:
# 测试示例 print(get_func_type(exte)) # 外部函数 bar = Foo() print(get_func_type(Foo.__init__)) # 实例函数(未绑定) print(get_func_type(Foo.stat)) # 静态方法 print(get_func_type(Foo.clas)) # 类方法 print(get_func_type(Foo.inst)) # 实例函数(未绑定) print(get_func_type(bar.__init__)) # 实例方法 print(get_func_type(bar.stat)) # 静态方法 print(get_func_type(bar.clas)) # 类方法 print(get_func_type(bar.inst)) # 实例方法 # 调用Getter/Setter时,装饰器中获取的func会被识别为对应类型
适配参数校验装饰器
基于上述类型判断,修改参数校验装饰器,实现自动跳过self/cls参数的校验:
import functools def type_check_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): func_type = get_func_type(func) # 需要跳过第一个参数的类型:实例方法、类方法、Getter、Setter skip_first = func_type in ["实例方法", "类方法", "Getter方法", "Setter方法"] # 获取函数签名和绑定的参数 sig = inspect.signature(func) try: bound_args = sig.bind(*args, **kwargs).arguments except TypeError as e: raise TypeError(f"参数不匹配: {e}") # 遍历参数进行类型校验 for param_name, param in sig.parameters.items(): # 跳过self/cls参数 if skip_first and param_name in ["self", "cls"]: continue # 如果有类型注解则校验 if param.annotation is not inspect.Parameter.empty: value = bound_args[param_name] if not isinstance(value, param.annotation): raise TypeError( f"参数 {param_name} 类型错误:预期 {param.annotation.__name__},实际 {type(value).__name__}" ) return func(*args, **kwargs) return wrapper
关键细节说明
- 绑定方法与未绑定函数:类中的实例方法在类层面是未绑定的
function,绑定到实例后才变成method;类方法在类层面就是绑定的method(绑定到类本身)。 - 静态方法:无论在类还是实例层面,静态方法始终是
function,需通过类属性判断是否为staticmethod实例。 - Getter/Setter:它们是
property对象的一部分,装饰器中拿到的是原始函数,需通过类属性找到对应的property,再判断是fget还是fset。
内容的提问来源于stack exchange,提问作者Carlos Adir
相关产品推荐
相关产品推荐

