为什么可以';我继承Python中的dict和Exception吗?

为什么可以';我继承Python中的dict和Exception吗?,python,multiple-inheritance,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. """ de

我上了以下课程:

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(),因为异常是基于旧类的

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


EDIT2:我正在Ubuntu8.10上使用cpython2.4。你知道这种信息很有用;-)。不管怎么说,这个小小的谜语已经把我的三个同事的嘴给堵住了。你将是我今天最好的朋友…

什么版本的Python

在2.5.1中,我甚至不能定义继承自
dict
Exception
的类:

>>> 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
>类foo(dict,异常):
...   通过
... 
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:调用元类基时出错
多个基地存在实例布局冲突
如果您使用的是旧版本,可能它在类型定义期间不执行此检查,冲突会在以后导致异常。

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


仍然对答案感兴趣;-)

异常和dict都是用C实现的

我想你可以用以下方法来测试:

>>> class C(object): pass
...
>>> '__module__' in C.__dict__
True
>>> '__module__' in dict.__dict__
False
>>> '__module__' in Exception.__dict__
False
由于
Exception
dict
对于如何在内部存储它们的数据有不同的想法,因此它们不兼容,因此不能同时从两者继承

在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
>类foo(dict,异常):
...     通过
... 
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:调用元类基时出错
多个基地存在实例布局冲突

这有什么问题

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'>
试试看:
提升约束失败(x=ValueError,y=Exception)
除约束失效外,e:
打印e['x']
打印e['y']

我几乎可以肯定,对于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'>
$python2.4
Python 2.4.4(#119009年2月19日09:13:34)
>>>类型(dict)
>>>类型(例外)
>>>类型(异常())
$python2.5
Python 2.5.4(r254:679162009年2月17日23:11:16)
>>>类型(例外)
>>>类型(异常())
在这两个版本中,正如消息所说,异常可以是类、实例(旧式类)或字符串(已弃用)

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

使用
集合。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()

您的解决方案意味着我必须使用magic方法(setitem、items、iteritems、len等)重写整个dictionary接口,这意味着手动添加十几个方法,我也必须对这些方法进行单元测试。您实际使用了所有dictionary功能吗?为什么不能使用e.failures显式引用附加的字典?我至少需要列出/迭代键、值、len和get.setitem的功能。但别担心,UserDict会这么做的,因为我不认为这段代码是一个瓶颈。。。无论如何,谢谢你的建议:-)那么,你需要五种方法:键、值、项和setitem?我不清楚你想做什么,以及“几十个”可能包含哪些内容。您是否考虑了其他方法或其他功能?如果您所说的是正确的,我们应该能够从V3中的Dict和Exception继承?正如Dave Costa在Python 2.5中提到的,Exception和Dict不能位于同一继承层次结构中,因为它们在C中实现,并且存储方式不同。这也适用于任何内置(新样式类)类型,即使在以前的版本中也是如此。Python2.6和Python3似乎没有改变这个主题,GvR在他的“Python2.2中统一类型和类”中警告了这一点,顺便说一句(请参见,
“您可以使用多重继承,但不能从不同的内置类型进行多重继承(例如,您不能创建同时从内置dict和list类型继承的类型)。”