Проблема, которая у вас здесь есть, на самом деле не относится к супер, а скорее к каргам.Если мы отбросим большую часть вашего кода и удалим супер, он будет выглядеть так:
class Hourly(Employee):
def __init__(self, rate=''):
self.rate = rate
some_crazy_function(**kwargs)
hourlystaff1 = Hourly('Bob', 'Foo', '23', 'M', '12/1/1980', '$15', '30')
Есть две очевидные проблемы: Функция __init__
получает больше аргументов, чем ожидалось, и в телеФункция __init__
является ссылкой на kwargs
, которая нигде не определена.В то время как здесь понимания **kwargs
(и его родного брата *args
) достаточно, чтобы решить проблему, супер и **kwargs
очень полезны вместе.Давайте сначала посмотрим, почему super
полезен.Давайте представим, что мы пишем некоторые обертки вокруг подпроцессов с некоторыми хорошими вспомогательными методами (архитектура, возможно, не совсем подходит для этой проблемы, но только когда-либо видение животных с наследованием также не супер полезно. Многократное наследование - действительно редкий случай, так что это трудночтобы привести хорошие примеры, которые не являются Animals, GameEntities или GUIwidgets):
class Process:
def __init__(self, exe):
self.exe = exe
self.run()
class DownloadExecutableBeforeProcess(Process):
def __init__(self, exe):
self.download_exe(exe)
Process.__init__(self, exe)
Здесь мы делаем наследование, и нам даже не нужно использовать super - мы можем просто явно использовать имя суперклассаи иметь поведение, которое мы хотим.Мы могли бы переписать, чтобы использовать super
здесь, но это не изменило бы поведение.Если вы наследуете только от одного класса, вам не нужен super
, хотя это может помочь вам не повторять имя класса, от которого вы наследуете.Давайте добавим к нашему классу хирархию и включим наследование более чем одного класса:
class AuthenticationCheckerProcess(Process):
def __init__(self, exe, use_sha=True):
self.check_if_authorized(exe, use_sha)
Process.__init__(self, exe)
class DownloadAndCheck(DownloadExecutableBefore, AuthenticationCheckerProcess):
def __init__(self, exe):
DownloadExecutableBefore.__init__(exe)
AuthenticationCheckerProcess.__init__(exe, use_sha=False)
Если мы следуем инициализации DownloadAndCheck
, мы видим, что Process.__init__
вызывается дважды, один раз через DownloadExecutableBefore.__init__
и один раздо AuthenticationCheckerProcess.__init__
!Так что наш процесс, который мы хотим обернуть, также запускается дважды, а это не то, что мы хотим.Здесь, в этом примере, мы могли бы легко это исправить, не вызывая self.run()
в init процесса, но в случаях реального мира это не всегда так легко исправить, как здесь.В этом случае вызов Process.__init__
кажется неправильным.Можем ли мы как-то это исправить?
class DownloadAndCheck(DownloadExecutableBefore, AuthenticationCheckerProcess):
def __init__(self, exe):
super().__init__(exe, use_sha=False)
# also replace the Process.__init__ cals in the other classes with super
super
исправит эту проблему и вызовет Process.__init__
только один раз.Он также позаботится о порядке, в котором должна выполняться функция, но здесь это не является большой проблемой.У нас все еще есть проблема: use_sha=False
будет передано всем инициализаторам, но на самом деле это нужно только одному.На самом деле мы не можем передать переменную только тем функциям, которые в ней нуждаются (потому что вычисление этого было бы кошмаром), но мы можем научить другие __init__
s просто игнорировать клавиатуру:
class Process:
def __init__(self, exe, **kwargs):
# accept arbitrary keywoards but ignore everything but exe
# also put **kwargs in all other initializers
self.exe = exe
self.run()
class DownloadExecutableBeforeProcess(Process):
def __init__(self, exe, **kwargs):
self.download_exe(exe)
# pass the keywoards into super so that other __init__s can use them
Process.__init__(self, exe, **kwargs)
Теперь вызов super().__init__(exe, use_sha=False)
будет успешным, каждый инициализатор берет только те ключевые слова, которые он понимает, и просто передает другие дальше.
Так что, если у вас есть множественное наследование и используются разные (keywoard) аргументы, супер и kwargs могут решитьтвоя проблема.Но супер и множественное наследование сложно, особенно если у вас больше уровней наследования, чем здесь.Иногда порядок, в котором функции должны быть вызваны, даже не определен (и тогда Python должен выдать ошибку, см., Например, объяснение изменения алгоритма MRO ).Для миксинов может даже потребоваться вызов super().__init__()
, хотя они даже не наследуются ни от одного класса.В целом вы получаете большую сложность в своем коде, если используете множественное наследование, поэтому, если оно вам действительно не нужно, часто лучше подумать о других способах моделирования вашей проблемы.