2016-12-27 2 views
3

У меня есть производный класс, метод __init__ которого вызывает только super().__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=''): 
     super().__init__(self, dataset, updater,start_date, end_date,fill_missing_only,total_sync,force,allow_missing,backfill) 

Есть ли способ, чтобы удалить это и есть подкласс называют инициализацию базы (в) метод автоматически?

+2

использовать '__init __ (самостоятельно, * арг ** kwargs): супер() .__ инициализацию __ (самостоятельно, * арг , ** kwargs) '? – yedpodtrzitko

ответ

3

Я вижу две возможности:

  • Просто опускаем метод __init__ в подклассе - если вы на самом деле не переопределяют ничего.

  • Использование

    def __init__(*args, **kwargs): 
        super().__init__(*args, **kwargs) 
    

    если вы делаете какие-то другие вещи, кроме super().__init__ вызова, но не нужно все аргументы.

+0

Однако OP делает аннотации типов по параметрам, и, возможно, их иордантные сохраняются. * Args, ** kwargs способ уничтожить подпись функции - аннотации и все. Сохранение это не очевидно, и если вы обнаружите хороший способ, это станет отличным ответом, даже если вопрос не так много. – jsbueno

+0

@jsbueno. Вы можете просто скопировать аннотации, например, через метакласс. Кроме того, первый вариант не потребует дополнительной работы в этом отношении. –

+0

Я не делаю ничего другого в методе, кроме вызова super(). Если я опускаю метод __init__ в подклассе, будет ли вызван метод super()? У меня создалось впечатление, что метод super() .__ init __() не вызывается автоматически. – user1742188

0

Проще всего было бы удалить ребенка __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 
Смежные вопросы