2016-12-27 72 views
3

我有一个派生类,其__init__方法只调用super().__init(...)。然而,参数的超类的列表非常长,这使得大部分锅炉板的一个长长的清单:子类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) 

有没有一种方法),除去这一点,并有子类调用基的init(方法自动?

+2

使用'__init __(自我,* ARGS,** kwargs):超().__的init __(自我,* ARGS ,** 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 
相关问题