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

如何在元类中判断类的方法是实例方法还是静态方法?

区分元类中的实例方法与静态方法的更优方案

你用检查第一个参数是否为self的方式确实有点脆弱——毕竟Python对参数名没有强制要求,有人会用this甚至别的名字,甚至偶尔会看到不写第一个参数的实例方法(虽然不规范,但语法上允许)。这里有几个更可靠的方案,都是基于Python标准库的,不用手动遍历继承树:

方案一:直接通过类型判断

从类上获取属性时,静态方法、类方法和实例方法的类型是不同的:

  • 静态方法是staticmethod类的实例,需要通过__func__拿到内部的函数
  • 类方法是classmethod类的实例
  • 实例方法则是普通的function对象(还没绑定到实例)

利用这个特性,我们可以修改元类的代码:

import inspect

class DecoratedMeta(type):
    def __new__(mcs, name, bases, attrs):
        cls = super().__new__(mcs, name, bases, attrs)
        
        for attr_name in dir(cls):
            attr = getattr(cls, attr_name)
            
            # 处理静态方法
            if isinstance(attr, staticmethod):
                func = attr.__func__
                if mcs.is_valid(func):
                    # 装饰后要重新包装成staticmethod
                    setattr(cls, attr_name, staticmethod(mcs.decorate(func)))
            
            # 处理实例方法(排除特殊方法和类方法)
            elif inspect.isfunction(attr) and not isinstance(attr, classmethod):
                # 可选:排除双下划线开头的特殊方法
                if not attr_name.startswith('__') and mcs.is_valid(attr):
                    setattr(cls, attr_name, mcs.decorate(attr))
        
        return cls
    
    @staticmethod
    def is_valid(func):
        # 这里写你的判断逻辑,比如排除某些函数
        return True
    
    @staticmethod
    def decorate(func):
        def wrapper(*args, **kwargs):
            print(f"Decorated: {func.__name__}")
            return func(*args, **kwargs)
        return wrapper

方案二:用inspect.getmembers过滤属性

inspect.getmembers可以帮你直接过滤出指定类型的成员,代码会更简洁:

import inspect

class DecoratedMeta(type):
    def __new__(mcs, name, bases, attrs):
        cls = super().__new__(mcs, name, bases, attrs)
        
        # 获取所有实例方法(普通函数,非静态/类方法)
        for attr_name, func in inspect.getmembers(cls, predicate=inspect.isfunction):
            if not attr_name.startswith('__') and mcs.is_valid(func):
                setattr(cls, attr_name, mcs.decorate(func))
        
        # 获取所有静态方法
        for attr_name, static_meth in inspect.getmembers(cls, predicate=lambda x: isinstance(x, staticmethod)):
            func = static_meth.__func__
            if mcs.is_valid(func):
                setattr(cls, attr_name, staticmethod(mcs.decorate(func)))
        
        return cls
    
    # is_valid 和 decorate 方法同上

为什么这两个方案更好?

  • 避免了参数名的依赖:不管实例方法的第一个参数叫self还是this,都能准确识别
  • 自动处理继承的属性:dir(cls)和inspect.getmembers都会包含基类的成员,不用手动遍历继承树
  • 类型判断更准确:直接利用Python的装饰器类型(staticmethod/classmethod)来区分,逻辑更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:10:58