Python 中的多重继承怪癖或错误?
Multiple Inheritance Quirk, or Bug in Python?
我正在写一个 class,它应该是 class,以及其他 classes,code.InteractiveInterpreter
。出于某种原因,当您使用多重继承时,class 通常具有的方法之一 (compile
) 在其子 class 上不可用。
单继承工作正常:
>>> 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 重现该问题,但我无法...这很好用:
>>> class Original():
... def compile(self): pass
...
>>> class Secondary(object, Original): pass
...
>>> hasattr(Secondary(), 'compile')
True
我在 Windows 10 上使用 Python 2.7.11,32 位。
您确定Flipped
产生了给定的结果吗?
我使用类似的设置得到以下结果,
>>> from code import InteractiveInterpreter
>>> class Flipped(InteractiveInterpreter, object): pass
...
>>> hasattr(Flipped(), 'compile')
True
基于 source of the module,compile
不是 class 的方法,而是实例属性 在对象初始化时创建。从 object
继承首先不会提供属性是有道理的,因为它定义了 __init__
并且 subclass 不调用 InteractiveInterpreter.__init__
来分配属性。
我不完全知道问题出在哪里,但一种解决方法是显式调用 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)] darwin
当你混合对象和旧样式时,它看起来像一些东西class
Python 2.7.6 Ubuntu 14.04
我检查了 code.InteractiveInterpreter 的代码(它使用的是旧样式 class),然后进行了一些测试:
(我刚刚导入了代码,然后通过 code.__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']
试图创建一个 'Fifth' class,我从对象和 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
我不确定为什么会这样,但这肯定与直接将对象与旧样式混合有关class。
我正在写一个 class,它应该是 class,以及其他 classes,code.InteractiveInterpreter
。出于某种原因,当您使用多重继承时,class 通常具有的方法之一 (compile
) 在其子 class 上不可用。
单继承工作正常:
>>> 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 重现该问题,但我无法...这很好用:
>>> class Original():
... def compile(self): pass
...
>>> class Secondary(object, Original): pass
...
>>> hasattr(Secondary(), 'compile')
True
我在 Windows 10 上使用 Python 2.7.11,32 位。
您确定Flipped
产生了给定的结果吗?
我使用类似的设置得到以下结果,
>>> from code import InteractiveInterpreter
>>> class Flipped(InteractiveInterpreter, object): pass
...
>>> hasattr(Flipped(), 'compile')
True
基于 source of the module,compile
不是 class 的方法,而是实例属性 在对象初始化时创建。从 object
继承首先不会提供属性是有道理的,因为它定义了 __init__
并且 subclass 不调用 InteractiveInterpreter.__init__
来分配属性。
我不完全知道问题出在哪里,但一种解决方法是显式调用 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)] darwin
当你混合对象和旧样式时,它看起来像一些东西class
Python 2.7.6 Ubuntu 14.04
我检查了 code.InteractiveInterpreter 的代码(它使用的是旧样式 class),然后进行了一些测试: (我刚刚导入了代码,然后通过 code.__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']
试图创建一个 'Fifth' class,我从对象和 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
我不确定为什么会这样,但这肯定与直接将对象与旧样式混合有关class。