Python实现经典装饰器模式 如何让被装饰实例通过原类isinstance校验
解决方案
你可以根据自己的场景选择以下两种常用实现方案:
方案1:重写__class__属性(最简单,无需修改原类)
Python的isinstance检查会优先读取实例的__class__属性做判断,只需要在抽象装饰器类中添加一个__class__属性的getter,直接返回被装饰实例的类型即可:
class AbstractDecorator: base_class: type = None def __init__(self, instance): self.instance = instance def __getattr__(self, item): # 若当前对象不存在对应属性或方法,则从被装饰的实例中查找 return getattr(self.instance, item) @property def __class__(self): # isinstance检查时直接返回被装饰实例的类型 return self.instance.__class__
测试效果:
original = Original() decorated = ConcreteDecorator(original) print(isinstance(decorated, Original)) # 输出 True
优劣说明:
- 优点:代码最少,不需要修改原类定义,多层装饰也能正常生效
- 缺点:会覆盖装饰器本身的类型判断,
isinstance(decorated, ConcreteDecorator)会返回False,如果不需要判断装饰器自身类型的场景最适合用这个方案。
方案2:虚拟子类注册(同时保留装饰器自身类型判断)
如果你需要同时支持isinstance(decorated, 原类)和isinstance(decorated, 装饰器类)两种判断,可以用Python的ABC虚拟子类机制:
- 给原类指定
ABCMeta元类 - 把具体装饰器类注册为原类的虚拟子类
from abc import ABCMeta # 原类指定ABCMeta元类 class Original(metaclass=ABCMeta): def __init__(self): self.some_val = 1 class ConcreteDecorator(AbstractDecorator): base_class = Original # 注册为原类的虚拟子类 Original.register(ConcreteDecorator)
测试效果:
original = Original() decorated = ConcreteDecorator(original) print(isinstance(decorated, Original)) # 输出 True print(isinstance(decorated, ConcreteDecorator)) # 输出 True
优劣说明:
- 优点:两种类型判断都能正常工作,完全符合Python的类型规范
- 缺点:需要修改原类的元类定义,如果原类是第三方库提供的无法修改的话不适用。
内容的提问来源于stack exchange,提问作者M1ha Shvn
相关产品推荐
相关产品推荐

