具有相同方法名但具有不同参数的多重继承会创建TypeError

时间:2016-09-14 18:51:50

标签: python class inheritance typeerror

我有四个不同的类。有一个主基/父类,两个从这个父类继承的主类,以及另一个继承自这两个主类的类。如果我有一个名称相同但参数数目不同的方法作为父类,我会得到一个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,即使它使用单个参数调用父类方法。

2 个答案:

答案 0 :(得分:1)

考虑这一行:

ChildTwo.method(self, arg)

您明确传入了selfself这里是对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()