Если у вас есть классы, которые будут составлены с другими классами, о которых они не должны знать (в частности, не нуждаются или не заботятся о своих аргументах), вы можете использовать **
Python Parameter /Синтаксис передачи аргументов для складывания и разворачивания аргументов в словарь.
Другими словами, ваш код будет выглядеть так:
class A:
def __init__(self, a, **kwargs):
self._a = a
super().__init__(**kwargs)
class B:
def __init__(self, b1, b2, **kwargs):
self._b1 = b1
self._b2 = b2
super().__init__(**kwargs)
class C(B, A):
def __init__(self, b1, b2, a):
super().__init__(b1=b1, b2=b2, a=a)
Также обратите внимание, что в ваших базовых классах __init__
код вышевы не вызывали super()
, поэтому когда-нибудь будет выполняться только __init__
из ближайшего суперкласса.
super()
в Python делает всю магию, необходимую для правильного работы множественного наследования. Одной из наиболее полных статей по этому вопросу по-прежнему является суперсчитаемый супер Python * .
Вкратце, что происходит: когда вы создаете класс, используя или не несколько родителей, Python создает __mro__
атрибут для него - это «порядок разрешения методов» для этого класса, указывающий порядок, в котором методы и атрибуты будут искать в предках.
Алгоритм вычисления самого MRO сложен, его немного объяснили, но ему можно разумно доверять, поскольку он "просто делает правильные вещи". До сегодняшнего дня единственное место, где я нашел его полное описание, это его оригинальная презентация в документации Python 2.3 , более 15 лет назад. (необязательное чтение, поскольку оно «делает правильные вещи».)
Что super()
делает, это создает прокси-объект, который выберет следующий класс в последовательности «mro» для исходного вызывающего класса, иМетоды поиска прямо в его __dict__
- если он не найден, он перейдет к следующей записи в «mro». Итак, если вы рассмотрите только класс B
, super().__init__()
внутри его тела вызовет object.__init__
. Если в этот момент «kwargs» пуст, как и в случае, если B()
вызывается только с теми параметрами, о которых он заботится, это именно то, что нужно.
Когда B.__init__
выполняется в цепочечном super()
вызове из класса "C", составленного из "B" и "A", кто бы то ни был, super()
в B.__init__
будет использовать "C"MRO - и следующий класс -" A "- поэтому A.__init__
вызывается со всеми неиспользованными аргументами ключевого слова.