I have a Parent
class with a default value for the attribute arg2
. I want to create a subclass Child
which has a different default value for the same attribute.
I need to use *args
and **kwargs
in Child
.
I tried the following, but it is not working:
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')
This is not working. In fact, I get:
>>> 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'
You need to set the default in kwargs
before passing it on to super()
; this is tricky as you need to ensure that the same value is not already in args
too:
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)
This relies on knowing how many arguments are there to fill however. You'd have to use introspection of super().__init__
for this to work in the general case:
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)
You'd be much better off specifying all defaults instead:
class Child(Parent):
def __init__(self, arg1='something', arg2='new value'):
super(Child, self).__init__(arg1=arg1, arg2=arg2)