最简单的事情就是完全删除孩子的__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 __(自我,* ARGS,** kwargs):超().__的init __(自我,* ARGS ,** kwargs)'? – yedpodtrzitko