将python修饰符应用于所有继承类

将python修饰符应用于所有继承类,python,django,Python,Django,在我的django项目(django 1.6-很快升级到1.9,python 2.7)中 我想在我的项目的所有模型类(20-30类)上应用一个装饰器。 所有这些类都已经从一个名为“LinkableModel”的父类继承,我编写这个父类是为了某种(不相关的)目的 现在,我想对所有这些模型应用一个类装饰器。 (具体地说,我指的是decorator‘python_2_unicode_compatible’:) 当我将此装饰器添加到其父类“LinkableModel”时,它不会被继承。 有没有办法将装饰

在我的django项目(django 1.6-很快升级到1.9,python 2.7)中

我想在我的项目的所有模型类(20-30类)上应用一个装饰器。 所有这些类都已经从一个名为“LinkableModel”的父类继承,我编写这个父类是为了某种(不相关的)目的

现在,我想对所有这些模型应用一个类装饰器。 (具体地说,我指的是decorator‘python_2_unicode_compatible’:)

当我将此装饰器添加到其父类“LinkableModel”时,它不会被继承。 有没有办法将装饰器应用于多个类,而不将其添加到每个类

(理论上,我甚至不介意这个装饰程序是否默认应用于我项目中的所有类…)

代码段:

@python_2_unicode_compatible
class LinkableModel(models.Model):
    ...
    ...
    ...

class MyModel1(LinkableModel):
    ...
    ...
    ...

class MyModel2(LinkableModel):
    ...
    ...
    ...
(据我所知)没有简单的方法,因为您不能继承decorators

我能想到的最简单的解决方案是:

globals_ = globals()
for name, cls in globals_.items():
    if subclass(cls, Base):
        globals_[name] = decorator(cls)
它只需迭代当前模块中已定义的每个全局变量,如果它恰好是从
Base
(或
Base
本身)继承的类,则使用
装饰器来装饰它

请注意,如果出现以下情况,则不会修饰子类:

  • 它是在这个片段之后创建的
  • 它是在另一个模块中创建的
  • 它未在全局命名空间中定义
或者,您可以使用元类:

class Decorate(type):
    def __new__(mcls, name, bases, attrs):
        return decorator(super().__new__(name, bases, attrs))

class Base(metaclass=Decorate):
    pass
编写
类基(metaclass=decoration):
时,Python使用
decoration
创建
Base
及其子类

decoration
所做的就是在返回类之前使用
decorator
来修饰类


如果使用此选项,如果您尝试从两个(或更多)类继承,每个类都有不同的元类,则可能会出现问题。

我使用@gingerplus的答案,并创建了以下函数,将装饰器应用于类的所有子类:

 def apply_decorator_to_all_subclasses(globals_, base_class, decorator):
    """
    Given a 'globals_' dictionary, a base class, and a decorator - this function applies the decorator to all the defined classes that derive from the base class
    Note!: this function should be called only *after* the subclassess were declared
    :param globals_: the given output of globals(), in the caller's context
    :param base_class: the class whose descendants require the decorator
    :param decorator: the decorator to apply
    """
    for name, cls in globals_.items():
        # Applying only on *class* items, that are descandants of base_class
        if inspect.isclass(cls) and issubclass(cls, base_class) and cls != base_class:
            globals_[name] = decorator(cls)

在Python 3.7中,现在可以这样做:

  class ParentClass:
      def __init_subclass__(cls, **kwargs):
          return your_decorator(_cls=cls)
它将为ParentClass的每个子类应用decorator

更新:完整示例:

def your_decorator(_cls):
    print("Hello, I'm decor!")
    def wrapper():
        return _cls()
    return wrapper


class ParentClass:
    def __init_subclass__(cls, **kwargs):
        return your_decorator(_cls=cls)


class A(ParentClass):
    pass

a = A()

元类
对于name,globals()中的cls。items():if issubclass(cls,Base):globals()[name]=decorator(cls)
?如果修饰模型,类迁移将不起作用。@GingerPlusPlus无法让它起作用,你能用一个代码片段详细说明一下吗?@AviahLaor我修饰了一个模型类,南迁移似乎仍然起作用。您能解释一下它们以什么方式不起作用吗?选择了第一个选项,但必须将第三行更改为:if inspect.isclass(cls)和issubclass(cls,Base)和cls!=Base:我真的很想这样做,但遗憾的是,一般来说似乎不行。使用dataclasses.dataclass作为装饰器似乎是可行的(但是init_子类的返回语句不是必需的,我不清楚返回语句实现了什么),但是当我使用自己的装饰器时就不行了(这一定是由于dataclass框架的某些行为)。我觉得这不是设计成这样的,init_子类不允许修改子类,而是父类。@kerzane,你好!我不确定这会导致问题。也许完整的例子会有帮助。我更新了答案,请检查。请确保,如果附加不适合您的代码,那么使用Python3.7运行代码会更有用谢谢您的回复!我的查询基于这样一个事实:当我在wrapper函数中添加print语句时:`def wrapper():print(“你好,我是wrapper!”)return _cls()`在实例化类a的对象时不会触发此print语句。另外,当我从init_子类方法中删除return语句时,代码的行为没有改变,所以我不确定从init_子类返回的对象是否有期望的结果