【问题标题】:How to write proper decorator to alter classes如何编写适当的装饰器来改变类
【发布时间】:2016-08-22 16:11:11
【问题描述】:

我知道我可以使用闭包和继承来创建一个改变类的装饰器。

def wrapper(cls, *args, **kwargs):
    class Wrapped(cls):
        """Modify your class here."""

    return Wrapped

但如果我需要测试我的新类以了解它们是否继承Wrapped,我无法访问Wrapped 本身来进行简单的isinstanceissubclass 测试。

另一方面,直接继承不是一种选择。我有大约 10 个不同的包装器需要添加到一个类中。这对层次结构树的负担太大了。

所以我需要一种从外部访问闭包的方法。或者另一种构建装饰器的方法。

【问题讨论】:

  • “但我需要测试我的新类以了解它们是否继承Wrapped”——我不确定为什么您需要对其进行测试。为什么不测试它们的行为是否正确?另请注意,装饰类将是Wrapped,因此如果您真的想要,可以测试DecoratedClass.__name__ == 'Wrapped',但这充其量只是一种黑客攻击。
  • 您的包装器可以添加某种标记方法吗?您可以测试标签是否存在。
  • 如果我有很多 wrapped 对象,则不能选择测试名称。你的意思是try 访问修改和catch 任何错误?
  • @John 这可能是一个选择。
  • @Claudiu 的出色回答正是我想到的。

标签: python decorator python-decorators


【解决方案1】:

听起来你想检查一个类是否被这个特定的装饰器包装了。最有效的方法可能是简单地为该效果添加一个字段,即:

def wrapper(cls, *args, **kwargs):
    class Wrapped(cls):
        """Modify your class here."""

    Wrapped._is_wrapped_by_this_wrapper = True
    return Wrapped

然后您可以检查hasattrgetattr_is_wrapped_by_this_wrapper

如果您有多个相互协作的包装类,您可能会想出一个可以更好地协同工作的解决方案,例如可能是一个set,由所有已应用的包装器名称组成。

【讨论】:

  • 有趣。它会解决我的问题。
【解决方案2】:

你可以从两个类继承,一个基类和cls

class WrapperBase:
    pass

def wrapper(cls, *args, **kwargs):
    class Wrapped(cls, WrapperBase):
        """Modify your class here."""

    return Wrapped

现在生成的类的所有实例都测试True for isinstance(obj, WrapperBase)

请注意,WrapperBase 对在 MRO 中查找继承的方法没有影响;它在任何层次结构中都排在最后(在 Python 2 上,不是从 object 继承的,所以它在 MRO 中排在最后,在 Python 3 中,它将位于 object 和包装的 MRO 中的 object 之前的任何内容之间类。

【讨论】:

  • 但是我进入了 MRO 冲突。当我需要向上继承树时会发生什么。 __init__ 浮现在脑海中。
  • @AlexandreParent: WrapperBase 没有定义任何方法。 super() 在查找__init__ 和其他方法时,WrapperBase 不会有问题。反正最后还是死了。
猜你喜欢
  • 2021-01-28
  • 1970-01-01
  • 2012-10-28
  • 2019-06-11
  • 2011-12-26
  • 2015-03-24
  • 2013-02-22
  • 2016-10-06
  • 2022-08-15
相关资源
最近更新 更多