子类init方法只调用基本初始化方法

时间:2016-12-27 19:37:36

标签: python python-3.x inheritance

我有一个派生类,__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)

有没有办法删除它并让子类自动调用基本的init()方法?

2 个答案:

答案 0 :(得分:3)

我看到两种可能性:

  • 只是省略了子类中的__init__方法 - 如果你实际上没有覆盖任何东西。

  • 使用

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

    除了super().__init__调用之外还做其他一些事情,但不需要所有参数。

答案 1 :(得分: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