A package I am using contains the class A. I want my new class B to inherit from this class. Minimal example:
class A():
def __init__(self,name):
self.name = name
def my_method(self):
return self.__class__(name = self.name)
class B(A):
def __init__(self, value, name):
self.value = value
super().__init__(name)
B_instance = B(value = 5, name = "Bob")
B_instance.my_method()
Calling the parent's method on the child throws:
File ..., line 5, in my_method
return self.__class__(name = self.name)
TypeError: __init__() missing 1 required positional argument: 'value'
How can I fix this without changing anything in class A? Many thanks for your help!
CodePudding user response:
A.my_method
assumes that A
(or any subclass thereof) can be instantiated with a single argument. You broke that assumption by adding a required argument value
to B.__init__
. You'll need to make value
the second parameter, and make it optional.
class B(A):
def __init__(self, name, value=None):
super().__init__(name)
self.value = value
Whether it is useful to use A.my_method
to create an instance of B
with value=None
is another question.
Let's pretend you could change A
. Then it would be better to design it to facilitate subclassing in the first place.
class A:
def __init__(self, *, name, **kwargs):
super().__init__(**kwargs)
self.name = name
@classmethod
def my_method(cls, **kwargs):
# Note: passing an explicit name argument will
# result in a TypeError on multiple arguments for
# the keyword argument 'name'
return cls(name="Alice", **kwargs)
Now you could define B
as
class B(A):
def __init__(self, *, value, **kwargs):
super().__init__(**kwargs)
self.value = value
a1 = A(name="Bob")
a2 = A.my_method() # A(name="Alice")
b1 = B(name="Joe", value=5)
b2 = B.my_method(value=10) # B(name="Alice", value=10)
This uses advice from https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ with regards to __init__
(and by extension, alternate class-method constructors):
- use keyword arguments when calling
- only handle your own parameters explicitly
- accept all unexpected keyword arguments to pass on to an ancestor class