在我的django项目中(django 1.6 - 很快升级到1.9,python 2.7),
我想在我所有项目的模型类(20-30个类)上应用装饰器。 所有这些类都已经从一个名为'LinkableModel'的父类继承而来,这是我为某个(非相关)目的而写的。
现在,我想将类装饰器应用于所有这些模型。 (具体来说,我指的是装饰者'python_2_unicode_compatible':https://docs.djangoproject.com/en/1.9/ref/utils/#django.utils.encoding.python_2_unicode_compatible)。
当我将这个装饰器添加到它们的父类'LinkableModel'时,它不会被继承。 有没有办法将装饰器应用于多个类,而不将其添加到每个类?
(从理论上讲,我甚至不介意这个装饰器是否默认应用于我项目中的所有类......)
代码段:
@python_2_unicode_compatible
class LinkableModel(models.Model):
...
...
...
class MyModel1(LinkableModel):
...
...
...
class MyModel2(LinkableModel):
...
...
...
答案 0 :(得分:1)
(据我所知)没有简单的方法,因为你不能继承装饰器。
我能想象的最简单的解决方案是:
globals_ = globals()
for name, cls in globals_.items():
if subclass(cls, Base):
globals_[name] = decorator(cls)
它只是迭代已经在当前模块中定义的每个全局变量,如果它恰好是继承自Base
(或Base
本身)的类,则用decorator
来装饰它。
请注意,如果符合以下条件,子类将不会被修饰:
或者,您可以使用元类:
class Decorate(type):
def __new__(mcls, name, bases, attrs):
return decorator(super().__new__(name, bases, attrs))
class Base(metaclass=Decorate):
pass
当您编写class Base(metaclass=Decorate):
时,Python使用Decorate
创建Base
及其子类。
Decorate
所做的就是在返回之前使用decorator
修饰类。
如果你使用它,如果你试图继承2个(或更多)类,每个类都有不同的元类,你可能会遇到问题。
答案 1 :(得分:0)
我使用了@GingerPlusPlus的答案,并创建了以下函数,将装饰器应用于类的所有子类:
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)
答案 2 :(得分:0)
现在在Python 3.7中,您可以通过以下方式做到这一点:
class ParentClass:
def __init_subclass__(cls, **kwargs):
return your_decorator(_cls=cls)
它将为ParentClass的每个子类应用装饰器