You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何区分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

关键细节说明

  1. 绑定方法与未绑定函数:类中的实例方法在类层面是未绑定的function,绑定到实例后才变成method;类方法在类层面就是绑定的method(绑定到类本身)。
  2. 静态方法:无论在类还是实例层面,静态方法始终是function,需通过类属性判断是否为staticmethod实例。
  3. Getter/Setter:它们是property对象的一部分,装饰器中拿到的是原始函数,需通过类属性找到对应的property,再判断是fget还是fset。

内容的提问来源于stack exchange,提问作者Carlos Adir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 04:50:48