I have a four distinct classes. There is a main base/parent class, two main classes that inherit from this parent class, and another class that inherits from both of these main classes. If I have a method with the same name but a different number of arguments as a parent class, I get a TypeError.
# Example
class Parent(object):
def check(self, arg):
tmp = {
'one': False,
'two': False
}
try:
if 'one' in arg:
tmp['one'] = True
if 'two' in arg:
tmp['two'] = True
except TypeError:
pass
return tmp
class Child(Parent):
def check(self, arg):
return Parent.check(self, arg)['one']
def method(self, arg):
if self.check(arg):
print 'One!'
class ChildTwo(Parent):
def check(self, arg):
return Parent.check(self, arg)['two']
def method(self, arg):
if self.check(arg):
print 'Two!'
class ChildThree(Child, ChildTwo):
def check(self, arg, arg2):
print arg2
return Child.check(self, arg)
def method(self, arg):
if self.check(arg, 'test'):
print 'One!'
ChildTwo.method(self, arg)
test = ChildThree()
test = test.method('one and two')
runfile('untitled6.py', wdir='./Documents')
test
One!
Traceback (most recent call last):
File "< stdin >", line 1, in < module >
File "C:\Users\py\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 714, in runfile
execfile(filename, namespace)
File "C:\Users\py\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 74, in execfile
exec(compile(scripttext, filename, 'exec'), glob, loc)
File "untitled6.py", line 49, in
test = test.method('one and two')
File "untitled6.py", line 46, in method
ChildTwo.method(self, arg)
File "untitled6.py", line 34, in method
if self.check(arg):TypeError: check() takes exactly 3 arguments (2 given)
However, when I remove the second argument from the 'check' method in 'ChildThree', it seems to work fine:
class ChildThree(Child, ChildTwo):
def check(self, arg):
return Child.check(self, arg)
def method(self, arg):
if self.check(arg):
print 'One!'
ChildTwo.method(self, arg)
runfile('untitled6.py', wdir='./Documents')
One!
Two!
I am fairly new to classes/inheritance, so I am not sure why an extra argument causes a TypeError even though it calls the parent class method with a single argument.
Consider this line:
ChildTwo.method(self, arg)
You passed in self explicitly. self here is a reference to a ChildThree instance. Later, in the body of ChildTwo.method:
if self.check(arg):
It's the same self we're talking about here; self is still a reference on your ChildThree instance.
It looks like you expected self to do something magical, but it doesn't - it's just a plain old name. For it to refer to a ChildTwo instance it would have had to be called like a bound method. Compare and contrast:
my_child_two.method(arg) <-- "self" gets passed implicitly by descriptor protocol ChildTwo.method(self, arg) <-- "self" is just whatever it is This type of inheritance is called "The Diamond Problem". It is a topic for itself, so I'll explain on a simpler case:
class C1(object):
def check(self, arg):
return 1
def method(self, arg):
return self.check(arg)
class C2(C1):
def check(self, arg1, arg2): # this overrides C1.check!
return x + C1.check(self, arg1)
c2 = C2()
c2.method(55) # fails
C2.check overrides C1.check on all C2 instances. Therefore, when self.check(arg) is called from method, it calls C2.check for instances of C2. That will fail because C2.check takes two arguments.
How to resolve that? When overriding methods, do not change their signature (number and type of received arguments and type of return value), or you'll get in trouble.
[more advanced] You could have more freedom with functions which take *args and **kwargs.
Besides that, I see that ChildThree.check calls Child.check which calls Parent.check, but noone calls ChildTwo.check. That cannot be right.
You should either call the method on all base classes (and risk calling the Parent implementation twice, which may even be right here), or use super().
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