多重继承Quirk,还是Python中的Bug?

时间:2016-02-14 01:41:07

标签: python inheritance multiple-inheritance

我正在编写一个类,它应该是其他类中的子类code.InteractiveInterpreter。出于某种原因,当您使用多重继承时,该类通常具有的某个方法(compile)在其子类上不可用。

单继承可以正常工作:

>>> from code import InteractiveInterpreter
>>> class Single(InteractiveInterpreter): pass
...
>>> hasattr(Single(), 'compile')
True

多重继承不会:

>>> class Double(object, InteractiveInterpreter): pass
...
>>> hasattr(Double(), 'compile')
False

虽然翻转了订单但是有效:

>>> class Flipped(InteractiveInterpreter, object): pass
...
>>> hasattr(Flipped(), 'compile')
True

是否有一些我不知道的多重继承的细微细节阻止compile在某些情况下被继承,或者Python中是否存在导致此问题的错误(给定相关方法的名称)也是内置函数的名称,我觉得这可能是可能的。)

我正在尝试使用InteractiveInterpreter以外的类重现该问题,但我无法...这样可以正常工作:

>>> class Original():
...     def compile(self): pass
...
>>> class Secondary(object, Original): pass
...
>>> hasattr(Secondary(), 'compile')
True

我在Windows 10上使用的是Python 2.7.11,32位。

3 个答案:

答案 0 :(得分:1)

您确定Flipped产生了给定的结果吗?

我通过类似的设置获得以下内容,

>>> from code import InteractiveInterpreter
>>> class Flipped(InteractiveInterpreter, object): pass
... 
>>> hasattr(Flipped(), 'compile')
True

基于source of the modulecompile 不是类的方法,而是在对象初始化时创建的实例属性。首先从object继承不会提供属性是有意义的,因为它定义了__init__并且子类没有调用InteractiveInterpreter.__init__来分配属性。

答案 1 :(得分:1)

我并不确切知道问题所在,但有一种解决方法是明确调用InteractiveInterpreter的构造函数,其中实际定义了compile方法:

class Double(object, InteractiveInterpreter):
    def __init__(self, *args, **kwargs):
        InteractiveInterpreter.__init__(self, *args, **kwargs)

请注意,简单地调用super(Double, self).__init__(...)是不够的(至少在我的环境中)。但是,这对我有用

>>> hasattr(Flipped(), 'compile')
True

我的环境: Python 2.7.11(默认,2016年1月5日,12:49:55) [达尔文的GCC 4.2.1兼容的Apple LLVM 7.0.2(clang-700.1.81)]

答案 2 :(得分:0)

当您混合对象和旧样式类时,它似乎是一种东西

Ubuntu 14.04上的Python 2.7.6

我检查了code.InteractiveInterpreter的代码(它使用旧的样式类),然后进行了一些测试: (我只是导入了代码,然后通过代码.__ file__找到了文件)

class Klass:
    def __init__(self):
        self.compile = 1

class Klass2(object):
    def __init__(self):
        self.compile = 1

class BlankObj:
    pass

class BlankObj2(object):
    pass


class Frist(object, Klass):
    pass

class Second(BlankObj, Klass):
    pass

class Thrid(BlankObj, Klass2):
    pass

class Fourth(BlankObj, Klass2):
    pass

然后玩弄这些物品:

>>> from testing import Frist, Second, Thrid, Fourth
>>> hasattr(Frist(), 'compile')
False
>>> hasattr(Second(), 'compile')
True
>>> hasattr(Thrid(), 'compile')
True
>>> hasattr(Fourth(), 'compile')
True
>>> 
>>> f = Frist()
>>> dir(f)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> s = Second()
>>> dir(s)
['__doc__', '__init__', '__module__', 'compile']

试图制作第五个' class,我从object继承而Klass2导致这个回溯:

>>> class Fifth(object, Klass2):
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases object, Klass2

我不确定为什么会发生这种情况,但它肯定与将对象直接与旧样式类混合有关。