我有四个不同的类。有一个主基/父类,两个从这个父类继承的主类,以及另一个继承自这两个主类的类。如果我有一个名称相同但参数数目不同的方法作为父类,我会得到一个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')
测试
一个!
追溯(最近的呼叫最后):
文件"< stdin>",第1行,<模块>
文件" C:\ Users \ py \ AppData \ Local \ Continuum \ Anaconda2 \ lib \ site-packages \ spyderlib \ widgets \ externalshell \ sitecustomize.py",第714行,在runfile中 execfile(filename,namespace)
文件" C:\ Users \ py \ AppData \ Local \ Continuum \ Anaconda2 \ lib \ site-packages \ spyderlib \ widgets \ externalshell \ sitecustomize.py",第74行,在execfile中 exec(compile(scripttext,filename,' exec'),glob,loc)
文件" untitled6.py",第49行,在 test = test.method('一个和两个')
文件" untitled6.py",第46行,方法
ChildTwo.method(self,arg)
文件" untitled6.py",第34行,方法
如果是self.check(arg):TypeError:check()只需要3个参数(给定2个)
然而,当我从'检查'中删除第二个参数时在ChildThree'中的方法,似乎工作正常:
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')
一个!
两个!
我对类/继承相当新,所以我不确定为什么额外的参数会导致TypeError,即使它使用单个参数调用父类方法。
答案 0 :(得分:1)
考虑这一行:
ChildTwo.method(self, arg)
您明确传入了self
。 self
这里是对ChildThree
实例的引用。后来,在ChildTwo.method
:
if self.check(arg):
我们在这里讨论的是self
; self
仍然是ChildThree
实例的参考。
看起来你期望self
做一些神奇的事情,但事实并非如此 - 这只是一个简单的旧名称。为了引用ChildTwo
实例,它必须像绑定方法一样被调用。比较和对比:
my_child_two.method(arg)
< - “self”由描述符协议隐式传递ChildTwo.method(self, arg)
< - “self”就是它的任何内容答案 1 :(得分:1)
这种类型的继承称为"The Diamond Problem"。这本身就是一个话题,所以我将在一个更简单的案例中解释:
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
会覆盖所有C2实例上的C1.check
。因此,当从self.check(arg)
调用method
时,它会为{C2}的实例调用C2.check
。这将失败,因为C2.check
有两个参数。
如何解决?覆盖方法时,不要更改其签名(接收的参数的数量和类型以及返回值的类型),否则您将遇到麻烦。
[更高级] 您可以更自由地使用*args
and **kwargs
的函数。
除此之外,我看到ChildThree.check
调用Child.check
调用Parent.check
,但没有人调用ChildTwo.check
。这不可能是正确的。
您应该在所有基类上调用该方法(并且可能会调用两次Parent实现,这可能就在这里),或者使用super()
。