2016-09-14 97 views
1

我有四个不同的类。有一个主基类/父类,从这个父类继承的两个主类,以及从这两个主类继承的另一个类。如果我有一个与父类相同的名称但参数个数不同的方法,我会得到一个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')
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)

然而,当我删除从 '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')
One!
Two!

我是相当新的类/继承,所以我不知道为什么一个额外的参数会导致TypeError,即使它调用具有单个参数的父类方法。

回答

1

考虑这条线:

ChildTwo.method(self, arg) 

您在self传递明确。 self这里是对ChildThree实例的引用。后来,在ChildTwo.method正文:

if self.check(arg): 

这是我们在这里讨论的相同self; self仍然是您的ChildThree实例的参考。

它看起来像你期望self做神奇的事情,但它不 - 它只是一个普通的旧名称。要引用ChildTwo实例,它必须被称为绑定方法。比较和对比:

  • my_child_two.method(arg) < - “自我”被通过描述协议隐式传递
  • ChildTwo.method(self, arg) < - “自我”只是不管它是
+0

啊,这很有道理!一旦允许我(等待3分钟),我会接受答案。有没有一种好的/ Pythonic的方法来解决这个问题,或者我只是将'ChildTwo.method'主体中的'self.check(arg):'改为'如果ChildTwo.check(self,arg)'? – PyNoob

+0

我建议的方式是避免在继承情况下使用相同名称和不同参数规范的方法。这听起来不必要的复杂,“pythonic”的很大一部分就是简单。 – wim

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覆盖C1.check所有C2实例。因此,当从method调用self.check(arg)时,它会针对C2的实例调用C2.check。这将失败,因为C2.check有两个参数。

如何解决?当重写方法时,不要更改它们的签名(接收参数的数量和类型以及返回值的类型),否则会遇到麻烦。

[更高级]你可以有更多的自由功能,需要*args and **kwargs


除此之外,我看到ChildThree.check电话Child.check这就要求Parent.check,但没有人叫ChildTwo.check。这是不对的。 您应该调用所有基类的方法(并且有可能调用父实现两次,这可能就在这里),或者使用super()

相关问题