在子类中更改默认构造函数参数值(从父类继承)

时间:2017-01-12 21:40:31

标签: python constructor arguments subclass

我有一个Parent类,其属性arg2的默认值。我想创建一个子类Child,它对同一个属性有不同的默认值。 我需要在*args中使用**kwargsChild

我尝试了以下操作,但它无效:

class Parent(object):
    def __init__(self, arg1='something', arg2='old default value'):
        self.arg1 = arg1
        self.arg2 = arg2

        print('arg1:', self.arg1)
        print('arg2:', self.arg2)

class Child(Parent):
    def __init__(self, *args, **kwargs):
        super(Child, self).__init__(*args, **kwargs)
        self.arg2 = kwargs.pop('arg2', 'new value')

这不起作用。事实上,我得到了:

>>> c = Child()
arg1: something
arg2: default value # This is still the old value
>>> c.arg2
'new value' # Seems more or less ok

>>> c = Child('one', 'two')
arg1: one
arg2: two
>>> c.arg2
'new value' # This is wrong, it has overridden the specified argument 'two'

2 个答案:

答案 0 :(得分:2)

您需要在super()中设置默认值,然后再将其传递给args;这很棘手,因为您需要确保class Child(Parent): def __init__(self, *args, **kwargs): if len(args) < 2 and 'arg2' not in kwargs: kwargs['arg2'] = 'new value' super(Child, self).__init__(*args, **kwargs) 中也没有相同的值:

super().__init__

这依赖于知道有多少参数可以填充。你必须使用from inspect import getargspec class Child(Parent): def __init__(self, *args, **kwargs): super_init = super().__init__ argspec = getargspec(super_init) arg2_index = argspec.args.index('arg2') - 1 # account for self if len(args) < arg2_index and 'arg2' not in kwargs: kwargs['arg2'] = 'new value' super(Child, self).__init__(*args, **kwargs) 的内省来解决这个问题:

class Child(Parent):
    def __init__(self, arg1='something', arg2='new value'):
        super(Child, self).__init__(arg1=arg1, arg2=arg2)

您最好不要指定所有默认值:

while

答案 1 :(得分:2)

你实际上改变了班级的签名。基本上,用:

def foo(a=1, b=2):
   ...

您可以按位置,按关键字调用:

foo(2, 3)
foo(a=2, b=3)

使用:

def bar(**kwargs):
   ...

你不能再使用位置参数调用:

bar(2, 3)  # TypeError!

您的实际代码还有其他复杂因素,因为您的*args占用了所有位置参数。

我能给你的最有力的建议是在覆盖方法时保留签名:

class Child(Parent):
    def __init__(self, arg1='something', arg2='new value'):
        super(Child, self).__init__(arg1=arg1, arg2=arg2)

这(很遗憾)并不是一个干嘛(不要重复自己),因为你可能喜欢 - 你必须指定'something'两次。您可以将其转换为全局常量,或更改Parent.__init__的签名。

或者,你可以做一些内省来处理父类的签名,以确保你以正确的方式传递正确的论点 - 但我非常怀疑它是什么?值得的。