In A.__init__
I call self.func(argument)
:
class A(object):
def __init__(self, argument, key=0):
self.func(argument)
def func(self, argument):
#some code here
I want to change the signature of A.func
in B
. B.func
gets called in B.__init__
through A.__init__
:
class B(A):
def __init__(self, argument1, argument2, key=0):
super(B, self).__init__(argument1, key) # calls A.__init__
def func(self, argument1, argument2):
#some code here
Clearly, this doesn't work because the signature of B.func
expects two arguments while A.__init__
calls it with one argument. How do I work around this? Or is there something incorrect with the way I have designed my classes?
key
is a default argument to A.__init__
. argument2
is not intended for key
. argument2
is an extra argument that B
takes but A
does not. B also takes key
and has default value for it.
Another constraint is that I would like not to change the signature of A.__init__
. key
will usually be 0
. So I want to allow users to be able to write A(arg)
rather than A(arg, key=0)
.
Generally speaking, changing the signature of a method between subclasses breaks the expectation that the methods on subclasses implement the same API as those on the parent.
However, you could re-tool your A.__init__
to allow for arbitrary extra arguments, passing those on to self.func()
:
class A(object):
def __init__(self, argument, *extra, **kwargs):
key = kwargs.get('key', 0)
self.func(argument, *extra)
# ...
class B(A):
def __init__(self, argument1, argument2, key=0):
super(B, self).__init__(argument1, argument2, key=key)
# ...
The second argument passed to super(B, self).__init__()
is then captured in the extra
tuple, and applied to self.func()
in addition to argument
.
In Python 2, to make it possible to use extra
however, you need to switch to using **kwargs
, otherwise key
is always going to capture the second positional argument. Make sure to pass on key
from B
with key=key
.
In Python 3, you are not bound by this restriction; put *args
before key=0
and only ever use key
as a keyword argument in calls:
class A(object):
def __init__(self, argument, *extra, key=0):
self.func(argument, *extra)
I'd give func()
an *extra
parameter too, so that it's interface essentially is going to remain unchanged between A
and B
; it just ignores anything beyond the first parameter passed in for A
, and beyond the first two for B
:
class A(object):
# ...
def func(self, argument, *extra):
# ...
class B(A):
# ...
def func(self, argument1, argument2, *extra):
# ...
Python 2 demo:
>>> class A(object):
... def __init__(self, argument, *extra, **kwargs):
... key = kwargs.get('key', 0)
... self.func(argument, *extra)
... def func(self, argument, *extra):
... print('func({!r}, *{!r}) called'.format(argument, extra))
...
>>> class B(A):
... def __init__(self, argument1, argument2, key=0):
... super(B, self).__init__(argument1, argument2, key=key)
... def func(self, argument1, argument2, *extra):
... print('func({!r}, {!r}, *{!r}) called'.format(argument1, argument2, extra))
...
>>> A('foo')
func('foo', *()) called
<__main__.A object at 0x105f602d0>
>>> B('foo', 'bar')
func('foo', 'bar', *()) called
<__main__.B object at 0x105f4fa50>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With