Reputation: 821
I have a subclass sharing the __ init __ of it's base class:
class SubClass(BaseClass)
def __init__(self, param, *args, **kwargs):
super().__init__(*args, **kwargs)
self.thing = param
The problem I have been having is the subclass __ init __ parameter "param" is being passed into the super().__init__(*args, **kwargs)
as an extra parameter. This usually gives me an error like:
TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given
I don't want that. I only want "param" to be used for these subclass instances. How do stop sending the extra param to the baseclass __ init __ while still being able to use it in the subclass __ init __? Example code to reproduce the issue:
from unittest import TestCase
class TestCaseSubClass(TestCase):
def __init__(self, param, *args, **kwargs):
super().__init__(*args, **kwargs) # Just use whatever is in TestCase's init + our stuff
self.thing = param
print(self.thing)
class TestClass(TestCaseSubClass(param='bdfbdfb')):
def test_stuff(self):
print('test stuff here')
Or with just raw python, no import, why cant I do this? (same error)
class A(object):
def __init__(self, athing='thing'):
self.thing = athing
print(self.thing)
class AB(A):
def __init__(self, param, *args, **kwargs):
super().__init__(*args, **kwargs)
self.param= param
print(self.param)
class ABC(AB(param='thh')):
pass
ABCinstance = ABC()
Upvotes: 0
Views: 171
Reputation: 76194
I'm interpreting this question as "how can I provide a default parameter to a subclass without defining an __init__
for it?". One possible way is to define the default value as a class attribute, which you access in the parent class' __init__
:
from unittest import TestCase
class TestCaseSubClass(TestCase):
_default_param = None
def __init__(self, *args, **kwargs):
param = kwargs.pop("param", self._default_param)
super().__init__(*args, **kwargs) # Just use whatever is in TestCase's init + our stuff
self.thing = param
class TestClass(TestCaseSubClass):
_default_param = "bdfbdfb"
def test_stuff(self):
print('test stuff here')
x = TestClass()
print(x.thing) #"bdfbdfb"
y = TestClass(param="foo")
print(y.thing) #"foo"
This approach doesn't quite match the argument format in your question, since now param
is a keyword-only argument, rather than a named positional argument. The principal practical difference is that you can't supply an argument for param
unless you refer to it by name: z = TestClass("foo")
won't do it, for example.
Based on the edits and comments to this question, another possible interpretation may be "How can I provide a parameter to a subclass that gets passed to the parent class, by any means necessary?", which has no requirement regarding default values. If you're willing to make param
a mandatory parameter, then you simply need to pass the value in when creating a TestClass instance:
from unittest import TestCase
class TestCaseSubClass(TestCase):
def __init__(self, param, *args, **kwargs):
super().__init__(*args, **kwargs) # Just use whatever is in TestCase's init + our stuff
self.thing = param
class TestClass(TestCaseSubClass):
def test_stuff(self):
print('test stuff here')
x = TestClass("bdfbdfb")
print(x.thing) #"bdfbdfb"
Upvotes: 1