为什么我不能继承Python中的dict和Exception?

时间:2008-11-21 15:37:42

标签: python multiple-inheritance

我得到了以下课程:

class ConstraintFailureSet(dict, Exception) :
    """
        Container for constraint failures. It act as a constraint failure itself
        but can contain other constraint failures that can be accessed with a dict syntax.
    """

    def __init__(self, **failures) :
        dict.__init__(self, failures)
        Exception.__init__(self)

print isinstance(ConstraintFailureSet(), Exception)
True
raise ConstraintFailureSet()
TypeError: exceptions must be classes, instances, or strings (deprecated), not ConstraintFailureSet

到底是什么?

最糟糕的是我不能尝试super(),因为Exception是基于旧的类......

编辑:是的,我试图切换继承/ init的顺序。

EDIT2:我在Ubuntu8.10上使用CPython 2.4。你刚才知道这种信息是有用的;-)。无论如何,这个小谜语已经关闭了我同事的三个口。你将成为我最好的朋友......

6 个答案:

答案 0 :(得分:21)

Exceptiondict都在C中实现。

我认为你可以用以下方式测试:

>>> class C(object): pass
...
>>> '__module__' in C.__dict__
True
>>> '__module__' in dict.__dict__
False
>>> '__module__' in Exception.__dict__
False

由于Exceptiondict对如何在内部存储数据有不同的想法,因此它们不兼容,因此您无法同时从两者继承。

在Python的更高版本中,您应该在尝试定义类时获得异常:

>>> class foo(dict, Exception):
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict

答案 1 :(得分:4)

这有什么问题?

class ConstraintFailure( Exception ):
    def __init__( self, **failures ):
        self.failures= failures # already a dict, don't need to do anything
    def __getitem__( self, key ):
        return self.failures.get(key)

这是一个例外,它在名为failures的内部字典中包含其他例外。

你可以更新你的问题,列出一些不能做的具体事情吗?

try:
    raise ConstraintFailure( x=ValueError, y=Exception )
except ConstraintFailure, e:
    print e['x']
    print e['y']


<type 'exceptions.ValueError'>
<type 'exceptions.Exception'>

答案 2 :(得分:3)

什么版本的Python?

在2.5.1中,我甚至无法定义继承自dictException的类:

>>> class foo(dict, Exception):
...   pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict

如果您使用的是旧版本,可能在类型定义期间没有进行此检查,并且冲突会导致以后出现异常情况。

答案 3 :(得分:3)

没有理由,只有解决方案

目前我仍然不知道原因,但我使用UserDict.UserDict绕过它。它的速度较慢,因为它是纯Python,但我不认为应用程序的这一部分会很麻烦。

仍然对答案感兴趣; - )

答案 4 :(得分:0)

我几乎可以肯定2.4问题是由旧样式类的异常引起的。

$ python2.4
Python 2.4.4 (#1, Feb 19 2009, 09:13:34)
>>> type(dict)
<type 'type'>
>>> type(Exception)
<type 'classobj'>
>>> type(Exception())
<type 'instance'>

$ python2.5
Python 2.5.4 (r254:67916, Feb 17 2009, 23:11:16)
>>> type(Exception)
<type 'type'>
>>> type(Exception())
<type 'exceptions.Exception'>

在两个版本中,消息说异常可以是类,实例(旧样式类)或字符串(不建议使用)。

从版本2.5开始,异常层次结构最终基于新的样式类。现在也允许从BaseException继承的新样式类的实例。 但是在2.4 Exception(旧样式类)和dict(新样式类)的多重继承中 导致新的样式类不允许作为例外(无论如何,混合旧的和新的样式类可能都是坏的。)

答案 5 :(得分:0)

使用collections.UserDict来避免元类冲突:

class ConstraintFailureSet(coll.UserDict, Exception):
        """
            Container for constraint failures. It act as a constraint failure itself
            but can contain other constraint failures that can be accessed with a dict syntax.
        """

        def __init__(self, **failures) :
            coll.UserDict.__init__(self, failures)
            Exception.__init__(self)


print( isinstance(ConstraintFailureSet(), Exception)) #True
raise ConstraintFailureSet()