В Python 2.5 есть способ создать декоратор, украшающий класс? В частности, я хочу использовать декоратор, чтобы добавить член в класс и изменить конструктор, чтобы он принимал значение для этого члена.
Ищете что-то вроде следующего (с синтаксической ошибкой в 'class Foo:':
def getId(self): return self.__id
class addID(original_class):
def __init__(self, id, *args, **kws):
self.__id = id
self.getId = getId
original_class.__init__(self, *args, **kws)
@addID
class Foo:
def __init__(self, value1):
self.value1 = value1
if __name__ == '__main__':
foo1 = Foo(5,1)
print foo1.value1, foo1.getId()
foo2 = Foo(15,2)
print foo2.value1, foo2.getId()
Я думаю, что мне действительно нужен способ сделать что-то вроде интерфейса C # в Python. Полагаю, мне нужно сменить парадигму.
источник
Помимо вопроса о том, являются ли декораторы классов правильным решением вашей проблемы:
В Python 2.6 и выше есть декораторы классов с @ -синтаксисом, поэтому вы можете написать:
В старых версиях это можно сделать по-другому:
Однако обратите внимание, что это работает так же, как для декораторов функций, и что декоратор должен возвращать новый (или измененный исходный) класс, что не является тем, что вы делаете в примере. Декоратор addID будет выглядеть так:
Затем вы можете использовать соответствующий синтаксис для вашей версии Python, как описано выше.
Но я согласен с другими, что наследование лучше подходит, если вы хотите переопределить
__init__
.источник
Никто не объяснил, что вы можете определять классы динамически. Таким образом, у вас может быть декоратор, который определяет (и возвращает) подкласс:
Что можно использовать в Python 2 (комментарий от Blckknght, объясняющий, почему вы должны продолжать делать это в версии 2.6+) следующим образом:
А в Python 3 вот так (но будьте осторожны при использовании
super()
в своих классах):Так что можете получить свой торт и съесть его - наследство и декораторы!
источник
super
вызовы в исходном классе. ЕслиFoo
бы у метода был назван вызывающий его методfoo
,super(Foo, self).foo()
он бы рекурсивно повторялся бесконечно, потому что имяFoo
привязано к подклассу, возвращаемому декоратором, а не к исходному классу (который недоступен по любому имени). Отсутствие аргументов в Python 3super()
позволяет избежать этой проблемы (я предполагаю, что с помощью той же магии компилятора, которая позволяет ему вообще работать). Вы также можете обойти проблему, вручную украсив класс под другим именем (как вы это делали в примере Python 2.5).Это не очень хорошая практика, и из-за этого нет механизма для этого. Правильный способ добиться желаемого - это наследование.
Загляните в документацию класса .
Небольшой пример:
Таким образом, у Босса есть все
Employee
, в том числе его собственный__init__
метод и собственные участники.источник
Я согласен с тем, что наследование лучше подходит для поставленной проблемы.
Я нашел этот вопрос действительно удобным при декорировании классов, спасибо всем.
Вот еще пара примеров, основанных на других ответах, в том числе о том, как наследование влияет на вещи в Python 2.7 (и @wraps , который поддерживает исходную строку документации функции и т. Д.):
Часто вы хотите добавить параметры в свой декоратор:
Выходы:
Я использовал декоратор функций, так как считаю их более лаконичными. Вот класс для украшения класса:
Более надежная версия, которая проверяет эти скобки и работает, если методы не существуют в декорированном классе:
В
assert
проверяет , что декоратор не используется без скобок. Если да, то декорируемый класс передаетсяmsg
параметру декоратора, который вызываетAssertionError
.@decorate_if
применяется толькоdecorator
если имеетcondition
значениеTrue
.Используются
getattr
,callable
test и@decorate_if
, чтобы декоратор не сломался, еслиfoo()
метод не существует в декорируемом классе.источник
На самом деле здесь есть довольно хорошая реализация декоратора классов:
https://github.com/agiliq/Django-parsley/blob/master/parsley/decorators.py
Я считаю, что это довольно интересная реализация. Поскольку он является подклассом класса, который он украшает, он будет вести себя точно так же, как этот класс, в таких вещах, как
isinstance
проверки.У этого есть дополнительное преимущество: это не редкость, когда
__init__
оператор в пользовательской форме django вносит изменения или дополнения,self.fields
поэтому лучше, чтобы измененияself.fields
произошли после того, как все они__init__
были выполнены для рассматриваемого класса.Очень умный.
Однако в вашем классе вы действительно хотите, чтобы украшение изменяло конструктор, что я не думаю, что это хороший вариант использования декоратора класса.
источник
Вот пример, который отвечает на вопрос о возврате параметров класса. Более того, он по-прежнему соблюдает цепочку наследования, т.е. возвращаются только параметры самого класса. Функция
get_params
добавлена в качестве простого примера, но другие функции могут быть добавлены благодаря модулю inspect.источник
В Django есть
method_decorator
декоратор, который превращает любой декоратор в декоратор метода, вы можете увидеть, как это реализовано вdjango.utils.decorators
:https://github.com/django/django/blob/50cf183d219face91822c75fa0a15fe2fe3cb32d/django/utils/decorators.py#L53
https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/#decorating-the-class
источник