18

我得到了以下课程:

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 是基于旧的类......

编辑:而且,是的,我试图切换继承/初始化的顺序。

EDIT2:我在 Ubuntu8.10 上使用 CPython 2.4。你更新知道这种信息很有用;-)。不管怎样,这个小谜语已经让我三个同事闭嘴了。你会是我今天最好的朋友...

4

6 回答 6

21

两者Exceptiondict用 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
于 2008-11-21T17:30:50.357 回答
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'>
于 2008-11-21T21:35:39.440 回答
3

什么版本的 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

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

于 2008-11-21T15:55:23.060 回答
3

没有理由,只有解决方案

目前我仍然不知道为什么,但我使用UserDict.UserDict. 由于它是纯 Python,因此速度较慢,但​​我认为在应用程序的这一部分上它不会很麻烦。

无论如何仍然对答案感兴趣;-)

于 2008-11-21T16:00:08.230 回答
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(新样式类)的多重继承导致新样式类不允许作为异常(无论如何混合旧样式类和新样式类可能很糟糕)。

于 2009-05-29T08:22:38.793 回答
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()
于 2015-12-17T12:30:02.037 回答