Как Python super() работает с множественным наследованием?
Я довольно новичок в объектно-ориентированном программировании на Python, и мне трудно понять super()
функция (новые классы стиля), особенно когда речь идет о множественном наследовании.
Например, если у вас есть что-то вроде:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
Что я не понимаю, так это: Third()
класс наследует оба метода конструктора? Если да, то какой из них будет работать с super() и почему?
А что, если вы хотите запустить другой? Я знаю, что это как-то связано с порядком разрешения методов Python ( MRO).
18 ответов
Это подробно описано с достаточным количеством подробностей самим Гвидо в его посте " Постановление о разрешении метода" (включая две более ранние попытки).
В вашем примере Third()
позвоню First.__init__
, Python ищет каждый атрибут в родительских классах, поскольку они перечислены слева направо. В этом случае мы ищем __init__
, Итак, если вы определите
class Third(First, Second):
...
Python начнет с просмотра First
, и если First
не имеет атрибута, то он будет смотреть на Second
,
Эта ситуация становится более сложной, когда наследование начинает пересекать пути (например, если First
унаследованный от Second
). Прочитайте ссылку выше для получения более подробной информации, но, в двух словах, Python будет пытаться поддерживать порядок, в котором каждый класс появляется в списке наследования, начиная с самого дочернего класса.
Так, например, если у вас было:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
MRO будет [Fourth, Second, Third, First].
Кстати: если Python не может найти согласованный порядок разрешения методов, он вызовет исключение, вместо того, чтобы вернуться к поведению, которое может удивить пользователя.
Отредактировано, чтобы добавить пример неоднозначного MRO:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Должен Third
MRO be [First, Second]
или же [Second, First]
? Нет очевидного ожидания, и Python выдаст ошибку:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Редактировать: я вижу, что несколько человек утверждают, что в приведенных выше примерах отсутствует super()
звонки, поэтому позвольте мне объяснить: цель примеров - показать, как строится MRO. Они не предназначены для печати "первая \ третья \ третья" или что-то еще. Вы можете - и должны, конечно, поиграться с примером, добавить super()
вызовы, посмотрите, что происходит, и получите более глубокое понимание модели наследования Python. Но моя цель здесь состоит в том, чтобы сделать это простым и показать, как строится MRO. И это построено, как я объяснил:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
Ваш код и другие ответы все глючат. Они пропускают super()
вызовы в первых двух классах, которые требуются для совместной работы подклассов.
Вот исправленная версия кода:
class First(object):
def __init__(self):
super(First, self).__init__()
print("first")
class Second(object):
def __init__(self):
super(Second, self).__init__()
print("second")
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print("third")
super()
вызов находит следующий метод в MRO на каждом шаге, поэтому у First и Second он тоже должен быть, иначе выполнение останавливается в конце Second.__init__()
,
Вот что я получаю:
>>> Third()
second
first
third
Я хотел немного развить ответ безжизненным, потому что, когда я начал читать о том, как использовать super() в иерархии множественного наследования в Python, я не получил его сразу.
Что вам нужно понять, так это super(MyClass, self).__init__()
обеспечивает следующий __init__
метод в соответствии с используемым алгоритмом Order Resolution Ordering (MRO) в контексте полной иерархии наследования.
Эта последняя часть имеет решающее значение для понимания. Давайте рассмотрим пример еще раз:
class First(object):
def __init__(self):
super(First, self).__init__()
print "first"
class Second(object):
def __init__(self):
super(Second, self).__init__()
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
В соответствии с этой статьей о порядке разрешения постановления Гвидо ван Россума, распоряжение о разрешении __init__
рассчитывается (до Python 2.3) с использованием "обхода слева направо в глубину":
Third --> First --> object --> Second --> object
После удаления всех дубликатов, кроме последнего, получаем:
Third --> First --> Second --> object
Итак, давайте проследим, что происходит, когда мы создаем экземпляр Third
класс, например x = Third()
,
По данным MRO
__init__
Третьего называется первым.Далее, согласно MRO, внутри
__init__
методsuper(Third, self).__init__()
решает до__init__
метод First, который вызывается.внутри
__init__
из первыхsuper(First, self).__init__()
вызывает__init__
Во-вторых, потому что это то, что диктует MRO!внутри
__init__
второйsuper(Second, self).__init__()
вызывает__init__
объекта, который составляет ничто. После этого"второй" печатается.После
super(First, self).__init__()
завершено, "первый" печатается.После
super(Third, self).__init__()
завершено, "это все" печатается.
Это подробно объясняет, почему создание экземпляра Third() приводит к:
>>> x = Third()
second
first
that's it
Алгоритм MRO был улучшен с Python 2.3 и выше, чтобы хорошо работать в сложных случаях, но я предполагаю, что использование "обхода слева направо в глубину" + "удаление дубликатов, ожидающих последнего" все еще работает в большинстве случаев (пожалуйста, комментарий, если это не так). Обязательно прочитайте пост в блоге Гвидо!
Это известно как проблема с бриллиантами, на странице есть запись на Python, но вкратце Python будет вызывать методы суперкласса слева направо.
В общем и целом
Предполагая, что все происходит от object
(если вы этого не сделаете), Python вычисляет порядок разрешения методов (MRO) на основе вашего дерева наследования классов. MRO удовлетворяет 3 свойствам:
- Дети класса приходят раньше своих родителей
- Левые родители идут раньше правых родителей
- Класс появляется только один раз в MRO
Если такого порядка не существует, ошибки Python. Внутренняя работа этого является C3 Linerization происхождения классов. Прочитайте все об этом здесь: https://www.python.org/download/releases/2.3/mro/
Таким образом, в обоих приведенных ниже примерах это:
- ребенок
- Оставил
- Правильно
- родитель
Когда вызывается метод, первое вхождение этого метода в MRO - это тот, который вызывается. Любой класс, который не реализует этот метод, пропускается. Любой звонок в super
внутри этого метода будет вызываться следующее вхождение этого метода в MRO. Следовательно, имеет значение как порядок, в котором вы размещаете классы в наследстве, так и то, куда вы помещаете вызовы. super
в методах.
С super
первый в каждом методе
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
print "parent"
class Left(Parent):
def __init__(self):
super(Left, self).__init__()
print "left"
class Right(Parent):
def __init__(self):
super(Right, self).__init__()
print "right"
class Child(Left, Right):
def __init__(self):
super(Child, self).__init__()
print "child"
Child()
Выходы:
parent
right
left
child
С super
последний в каждом методе
class Parent(object):
def __init__(self):
print "parent"
super(Parent, self).__init__()
class Left(Parent):
def __init__(self):
print "left"
super(Left, self).__init__()
class Right(Parent):
def __init__(self):
print "right"
super(Right, self).__init__()
class Child(Left, Right):
def __init__(self):
print "child"
super(Child, self).__init__()
Child()
Выходы:
child
left
right
parent
Я понимаю, что это не отвечает прямо super()
вопрос, но я чувствую, что это достаточно важно, чтобы поделиться.
Существует также способ прямого вызова каждого унаследованного класса:
class First(object):
def __init__(self):
print '1'
class Second(object):
def __init__(self):
print '2'
class Third(First, Second):
def __init__(self):
Second.__init__(self)
Просто отметьте, что если вы сделаете это таким образом, вам придется звонить каждому вручную, я уверен First
"s __init__()
не будет звонить.
Это то, как я решил проблему множественного наследования с разными переменными для инициализации и наличия нескольких MixIns с одним и тем же вызовом функции. Я должен был явно добавить переменные к переданным **kwargs и добавить интерфейс MixIn, чтобы быть конечной точкой для супер вызовов.
Вот A
является расширяемым базовым классом и B
а также C
классы MixIn, которые предоставляют функцию f
, A
а также B
оба ожидают параметра v
в их __init__
а также C
надеется w
, Функция f
принимает один параметр y
, Q
наследует от всех трех классов. MixInF
это миксин интерфейс для B
а также C
,
class A(object):
def __init__(self, v, *args, **kwargs):
print "A:init:v[{0}]".format(v)
kwargs['v']=v
super(A, self).__init__(*args, **kwargs)
self.v = v
class MixInF(object):
def __init__(self, *args, **kwargs):
print "IObject:init"
def f(self, y):
print "IObject:y[{0}]".format(y)
class B(MixInF):
def __init__(self, v, *args, **kwargs):
print "B:init:v[{0}]".format(v)
kwargs['v']=v
super(B, self).__init__(*args, **kwargs)
self.v = v
def f(self, y):
print "B:f:v[{0}]:y[{1}]".format(self.v, y)
super(B, self).f(y)
class C(MixInF):
def __init__(self, w, *args, **kwargs):
print "C:init:w[{0}]".format(w)
kwargs['w']=w
super(C, self).__init__(*args, **kwargs)
self.w = w
def f(self, y):
print "C:f:w[{0}]:y[{1}]".format(self.w, y)
super(C, self).f(y)
class Q(C,B,A):
def __init__(self, v, w):
super(Q, self).__init__(v=v, w=w)
def f(self, y):
print "Q:f:y[{0}]".format(y)
super(Q, self).f(y)
О комментарии @ Calfzhou, вы можете использовать, как обычно, **kwargs
:
class A(object):
def __init__(self, a, *args, **kwargs):
print("A", a)
class B(A):
def __init__(self, b, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
print("B", b)
class A1(A):
def __init__(self, a1, *args, **kwargs):
super(A1, self).__init__(*args, **kwargs)
print("A1", a1)
class B1(A1, B):
def __init__(self, b1, *args, **kwargs):
super(B1, self).__init__(*args, **kwargs)
print("B1", b1)
B1(a1=6, b1=5, b="hello", a=None)
Результат:
A None
B hello
A1 6
B1 5
Вы также можете использовать их позиционно:
B1(5, 6, b="hello", a=None)
но вы должны помнить MRO, это действительно сбивает с толку.
Я могу быть немного раздражающим, но я заметил, что люди забыли каждый раз использовать *args
а также **kwargs
когда они переопределяют метод, в то время как это один из немногих действительно полезных и разумных способов использования этих "магических переменных".
Еще один не охваченный вопрос - передача параметров для инициализации классов. С момента назначения super
В зависимости от подкласса единственный хороший способ передать параметры - это собрать их все вместе. Тогда будьте осторожны, чтобы не иметь одинаковое имя параметра с разными значениями.
Пример:
class A(object):
def __init__(self, **kwargs):
print('A.__init__')
super().__init__()
class B(A):
def __init__(self, **kwargs):
print('B.__init__ {}'.format(kwargs['x']))
super().__init__(**kwargs)
class C(A):
def __init__(self, **kwargs):
print('C.__init__ with {}, {}'.format(kwargs['a'], kwargs['b']))
super().__init__(**kwargs)
class D(B, C): # MRO=D, B, C, A
def __init__(self):
print('D.__init__')
super().__init__(a=1, b=2, x=3)
print(D.mro())
D()
дает:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D.__init__
B.__init__ 3
C.__init__ with 1, 2
A.__init__
Вызов суперкласса __init__
напрямую к более прямому назначению параметров заманчиво, но не получается, если есть super
вызов в суперклассе и / или MRO изменяется, и класс A может вызываться несколько раз, в зависимости от реализации.
В заключение: кооперативное наследование, супер и специфические параметры для инициализации не очень хорошо работают вместе.
Рассмотрите возможность звонка super().Foo()
вызывается из подкласса. Метод "Порядок разрешения методов" (MRO)- это порядок, в котором разрешаются вызовы методов.
Случай 1: одиночное наследование
В этом случае super().Foo() будет найден в иерархии и рассмотрит ближайшую реализацию, если она найдена, иначе вызовет исключение. Отношение "есть" всегда будет истинным между любым посещаемым подклассом и его суперклассом вверху иерархии. Но эта история не всегда одинакова для множественного наследования.
Случай 2: множественное наследование
Здесь, реализация при поиске супер ().Foo(), каждый посетил класс в иерархии может или не может иметьэто отношение. Рассмотрим следующие примеры:
class A(object): pass
class B(object): pass
class C(A): pass
class D(A): pass
class E(C, D): pass
class F(B): pass
class G(B): pass
class H(F, G): pass
class I(E, H): pass
Вот,I
это самый низкий класс в иерархии. Схема иерархии и ТОиР дляI
будет
(Красные цифры, показывающие ТОиР)
ТОиРI E C D A H F G B object
Обратите внимание, что классX
будет посещаться только в том случае, если были посещены все его подклассы, которые наследуют от него (т. е. вы никогда не должны посещать класс, в который стрелка входит из класса ниже, который вы еще не посещали).
Здесь обратите внимание, что после посещения класса C
, D
посещается, хотя C
а также D
DO NOT естьэто отношения между ними (но оба имеют сA
). Это гдеsuper()
отличается от одиночного наследования.
Рассмотрим немного более сложный пример:
(Красные цифры, показывающие ТОиР)
ТОиР I E C H D A F G B object
В этом случае мы исходим из I
к E
к C
. Следующим шагом будетA
, но мы еще не побывали D
, подкласс A
. Мы не можем посетитьD
, однако, поскольку мы еще не посетили H
, подкласс D
. ЛистьяH
как следующий класс для посещения. Помните, мы пытаемся подняться по иерархии, если возможно, поэтому мы посещаем его самый левый суперкласс,D
. ПослеD
мы посетили A
, но мы не можем подойти к объекту, потому что нам еще предстоит посетить F
, G
, а также B
. Эти классы, по порядку, завершают MRO дляI
.
Обратите внимание, что ни один класс не может появляться в MRO более одного раза.
Вот как super () выглядит в иерархии наследования.
Кредиты на ресурсы: Ричард Л. Холтерман Основы программирования на Python
В случае, когда каждый класс, от которого вы пытаетесь наследовать, имеет собственные позиционные аргументы для его init, просто вызовите собственный метод init каждого класса и не используйте super при попытке наследования от нескольких объектов.
class A():
def __init__(self, x):
self.x = x
class B():
def __init__(self, y, z):
self.y = y
self.z = z
class C(A, B):
def __init__(self, x, y, z):
A.__init__(self, x)
B.__init__(self, y, z)
>>> c = C(1,2,3)
>>>c.x, c.y, c.z
(1,2,3)
Рассмотрим дочерний элемент, где родители и имеют аргументы ключевого слова в своих конструкторах.
A B
\ /
AB
Для инициализации вам нужно явно вызвать конструкторы родительского класса вместо использования
super()
.
Пример:
class A():
def __init__(self, a="a"):
self.a = a
print(f"a={a}")
def A_method(self):
print(f"A_method: {self.a}")
class B():
def __init__(self, b="b"):
self.b = b
print(f"b={b}")
def B_method(self):
print(f"B_method: {self.b}")
def magical_AB_method(self):
print(f"magical_AB_method: {self.a}, {self.b}")
class AB(A,B):
def __init__(self, a="A", b="B"):
# super().__init__(a=a, b=b) # fails!
A.__init__(self,a=a)
B.__init__(self,b=b)
self.A_method()
self.B_method()
self.magical_AB_method()
A()
>>> a=a
B()
>>> b=b
AB()
>>> a=A
>>> b=B
>>> A_method: A
>>> B_method: B
Чтобы продемонстрировать, что двое родителей объединены в ребенка, рассмотрим
magical_AB_method
определен внутри класса. При вызове из экземпляра
B
, метод не работает, поскольку у него нет доступа к переменным-членам внутри. Однако при вызове из экземпляра дочернего элемента
AB
, этот метод работает, поскольку он унаследовал требуемую переменную-член от
A
.
B().magical_AB_method()
>>> AttributeError: 'B' object has no attribute 'a'
AB().magical_AB_method()
>>> magical_AB_method: A, B
В Python 3.5+ наследование выглядит предсказуемо и очень приятно для меня. Пожалуйста, посмотрите на этот код:
class Base(object):
def foo(self):
print(" Base(): entering")
print(" Base(): exiting")
class First(Base):
def foo(self):
print(" First(): entering Will call Second now")
super().foo()
print(" First(): exiting")
class Second(Base):
def foo(self):
print(" Second(): entering")
super().foo()
print(" Second(): exiting")
class Third(First, Second):
def foo(self):
print(" Third(): entering")
super().foo()
print(" Third(): exiting")
class Fourth(Third):
def foo(self):
print("Fourth(): entering")
super().foo()
print("Fourth(): exiting")
Fourth().foo()
print(Fourth.__mro__)
Выходы:
Fourth(): entering
Third(): entering
First(): entering Will call Second now
Second(): entering
Base(): entering
Base(): exiting
Second(): exiting
First(): exiting
Third(): exiting
Fourth(): exiting
(<class '__main__.Fourth'>, <class '__main__.Third'>, <class '__main__.First'>, <class '__main__.Second'>, <class '__main__.Base'>, <class 'object'>)
Как видите, он вызывает foo ровно ОДИН раз для каждой унаследованной цепочки в том же порядке, в котором она была унаследована. Вы можете получить этот заказ по телефону .MR:
Четвертый -> Третий -> Первый -> Второй -> База -> объект
class First(object):
def __init__(self, a):
print "first", a
super(First, self).__init__(20)
class Second(object):
def __init__(self, a):
print "second", a
super(Second, self).__init__()
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(10)
print "that's it"
t = Third()
Выход
first 10
second 20
that's it
Call to Third() определяет местоположение инициализации, определенной в Third. И вызов super в этой процедуре вызывает init, определенный в First. MRO=[Первый, Второй]. Теперь вызов super в init, заданном в First, продолжит поиск MRO и найдет init, определенный в Second, и любой вызов super попадет в объект init по умолчанию. Я надеюсь, что этот пример проясняет концепцию.
Если вы не позвоните супер из Первого. Цепь останавливается, и вы получите следующий вывод.
first 10
that's it
Я хотел бы добавить к тому, что @Visionscaper говорит вверху:
Third --> First --> object --> Second --> object
В этом случае интерпретатор не отфильтровывает объектный класс, потому что он дублирован, а скорее потому, что Second появляется в позиции головы и не появляется в хвостовой позиции в подмножестве иерархии. Пока объект появляется только в хвостовых позициях и не считается сильной позицией в алгоритме C3 для определения приоритета.
Линеаризация (MRO) класса C, L(C), является
- Класс С
- плюс слияние
- линеаризация его родителей P1, P2, .. = L(P1, P2, ...) и
- список его родителей P1, P2,..
Линейное слияние выполняется путем выбора общих классов, которые появляются в качестве заголовка списков, а не хвоста, поскольку порядок имеет значение (станет ясно ниже)
Линеаризация третьего может быть вычислена следующим образом:
L(O) := [O] // the linearization(mro) of O(object), because O has no parents
L(First) := [First] + merge(L(O), [O])
= [First] + merge([O], [O])
= [First, O]
// Similarly,
L(Second) := [Second, O]
L(Third) := [Third] + merge(L(First), L(Second), [First, Second])
= [Third] + merge([First, O], [Second, O], [First, Second])
// class First is a good candidate for the first merge step, because it only appears as the head of the first and last lists
// class O is not a good candidate for the next merge step, because it also appears in the tails of list 1 and 2,
= [Third, First] + merge([O], [Second, O], [Second])
// class Second is a good candidate for the second merge step, because it appears as the head of the list 2 and 3
= [Third, First, Second] + merge([O], [O])
= [Third, First, Second, O]
Таким образом, для реализации super() в следующем коде:
class First(object):
def __init__(self):
super(First, self).__init__()
print "first"
class Second(object):
def __init__(self):
super(Second, self).__init__()
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
становится очевидным, как этот метод будет решен
Third.__init__() ---> First.__init__() ---> Second.__init__() --->
Object.__init__() ---> returns ---> Second.__init__() -
prints "second" - returns ---> First.__init__() -
prints "first" - returns ---> Third.__init__() - prints "that's it"
В learningpyhonthehardway я изучаю нечто, называемое super() встроенной функцией, если не ошибаюсь. Вызов функции super() может помочь наследованию пройти через родителя и "родных братьев и сестер" и помочь вам увидеть яснее. Я все еще новичок, но я люблю делиться своим опытом использования этого super() в python2.7.
Если вы прочитали комментарии на этой странице, вы услышите о Порядке разрешения методов (MRO), метод, который является функцией, которую вы написали, MRO будет использовать схему Depth-First-Left-to-Right для поиска и запуска. Вы можете сделать больше исследований по этому вопросу.
Добавляя функцию super()
super(First, self).__init__() #example for class First.
Вы можете соединить несколько экземпляров и "семейств" с помощью super(), добавив каждый из них. И он выполнит методы, пройдет через них и убедится, что вы не пропустили! Однако добавление их до или после имеет значение, вы узнаете, выполнили ли вы упражнение learningpythonthehardway 44. Пусть начнется веселье!!
Принимая пример ниже, вы можете скопировать и вставить и попробовать запустить его:
class First(object):
def __init__(self):
print("first")
class Second(First):
def __init__(self):
print("second (before)")
super(Second, self).__init__()
print("second (after)")
class Third(First):
def __init__(self):
print("third (before)")
super(Third, self).__init__()
print("third (after)")
class Fourth(First):
def __init__(self):
print("fourth (before)")
super(Fourth, self).__init__()
print("fourth (after)")
class Fifth(Second, Third, Fourth):
def __init__(self):
print("fifth (before)")
super(Fifth, self).__init__()
print("fifth (after)")
Fifth()
Как это работает? Экземпляр пятого () будет следующим образом. Каждый шаг идет от класса к классу, где добавлена супер функция.
1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)
Родитель был найден, и он будет продолжаться до третьего и четвертого!!
5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)
Теперь все классы с super() были доступны! Родительский класс был найден и выполнен, и теперь он продолжает распаковывать функцию в наследованиях для завершения кодов.
9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed
Результат программы выше:
fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)
Для меня добавление super() позволяет мне увидеть, как python будет выполнять мое кодирование, и убедиться, что наследование может получить доступ к методу, который я намеревался.
Отправляю этот ответ для моей будущей ссылки.
Множественное наследование Python должно использовать модель ромба, и подпись функции не должна изменяться в модели.
A
/ \
B C
\ /
D
Фрагмент кода примера будет: -
class A:
def __init__(self, name=None):
# this is the head of the diamond, no need to call super() here
self.name = name
class B(A):
def __init__(self, param1='hello', **kwargs):
super().__init__(**kwargs)
self.param1 = param1
class C(A):
def __init__(self, param2='bye', **kwargs):
super().__init__(**kwargs)
self.param2 = param2
class D(B, C):
def __init__(self, works='fine', **kwargs):
super().__init__(**kwargs)
print(f"{works=}, {self.param1=}, {self.param2=}, {self.name=}")
d = D(name='Testing')
Здесь класс А object
Может быть, есть еще что-то, что можно добавить, небольшой пример с Django rest_framework и декораторами. Это дает ответ на неявный вопрос: "зачем мне это вообще?"
Как уже было сказано: мы используем Django rest_framework, и мы используем общие представления, и для каждого типа объектов в нашей базе данных мы обнаруживаем, что один класс представления предоставляет GET и POST для списков объектов, а другой класс представления предоставляет GET., PUT и DELETE для отдельных объектов.
Теперь POST, PUT и DELETE, которые мы хотим украсить, добавив логин_required Django. Обратите внимание, как это касается обоих классов, но не всех методов в каждом классе.
Решение могло пройти через множественное наследование.
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
class LoginToPost:
@method_decorator(login_required)
def post(self, arg, *args, **kwargs):
super().post(arg, *args, **kwargs)
То же самое и для других методов.
В список наследования моих конкретных классов я бы добавил свой LoginToPost
перед ListCreateAPIView
а также LoginToPutOrDelete
перед RetrieveUpdateDestroyAPIView
. Мои конкретные занятия 'get
останется без украшений.