如何编写适当的装饰器来改变类

时间:2016-08-22 16:11:11

标签: python decorator python-decorators

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

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

    return Wrapped

但是,如果我需要测试我的新课程以了解他们是否继承Wrapped,我无法访问Wrapped本身来做一个直截了当的isinstance或{{1} }测试。

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

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

2 个答案:

答案 0 :(得分:2)

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

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

    Wrapped._is_wrapped_by_this_wrapper = True
    return Wrapped

然后,您可以查看hasattr的{​​{1}}和getattr

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

答案 1 :(得分:1)

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

class WrapperBase:
    pass

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

    return Wrapped

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

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