Проще всего было бы удалить ребенка __init__
вообще. Родительский __init__
будет называться автоматически, и аннотации будут сохранены. Помните, что __init__
- это всего лишь метод, и поэтому он должен быть MRO так же, как и любой другой метод. Этот подход работает только в том случае, если дочерний элемент __init__
имеет ту же подпись, что и родительский, и не требует каких-либо дополнительных функций.
Если ребенок имеет ту же сигнатуру для __init__
, но не требует дополнительных аргументов, вы можете сделать что-то вроде этого:
def __init__(*args, **kwargs):
# Do stuff here
super().__init__(*args, *kwargs)
# Do stuff here
Единственная проблема в том, что аннотации материнской компании не сохраняются в данном случае. Вы можете скопировать поверх атрибута __annotations__
от родителя напрямую, если это имеет к вам значение, поскольку функция __annotations__
является изменяемым и присваиваемым словарем. Самый простой способ убедиться, что это делается последовательно, вероятно, будет с декоратора:
def copy_annotations(parent_fn):
def annotator(fn):
fn.__annotations__ = parent_fn.__annontations__
return fn
return annotator
...
@copy_annotations(Parent.__init__)
def __init__(self, *args, **kwargs):
...
super().__init__(*args, **kwargs)
Если ребенок не имеет ту же сигнатуру в качестве родителя (т.е. он имеет дополнительные параметры), попробуйте поставить эти параметры первый. Например, если это __init__
подпись родителя
def __init__(self, dataset, updater=None,
start_date=None,
end_date=None,
fill_missing_only=False,
total_sync: bool = False,
force: bool = False,
allow_missing: bool = False,
backfill=''):
вы могли бы определить ребенка следующим образом:
def __init__(self, child_param1: int = 0,
child_param2: bool = False,
*args, **kwargs):
# Do stuff with child_param1, child_param2
super().__init__(*args, **kwargs)
Если вам нужно смешать заказ вверх (так, чтобы ребенок аргументы не все первые), вам, возможно, придется выполнить математическую математику, чтобы получить желаемый результат. Например, если dataset
должен быть первым аргументом ребенка __init__
, можно определить так:
def __init__(self, dataset,
child_param1: int = 0,
child_param2: bool = False,
*args, **kwargs):
# Do stuff with child_param1, child_param2
super().__init__(*((dataset,) + args), **kwargs)
Это работает, потому что args
всегда tuple
, так что вы можете предварять (dataset,)
к нему перед распаковкой. Этот метод также будет работать, если вы вычислите некоторые аргументы родительскому объекту на основе аргументов дочернего элемента.
Если вы все еще хотите сохранить аннотации, декоратор для этого будет немного сложнее. Вместо того, чтобы копировать атрибут родительского __annotations__
, вы хотите, чтобы объединить его с существующим словарем:
def copy_annotations(parent_fn):
def annotator(fn):
original = fn.__annotations__
fn.__annotations__ = parent_fn.__annontations__
fn.__annotations__.update(original)
return fn
return annotator
использовать '__init __ (самостоятельно, * арг ** kwargs): супер() .__ инициализацию __ (самостоятельно, * арг , ** kwargs) '? – yedpodtrzitko