简体   繁体   English

Python:在异常实例中覆盖__str__

[英]Python: override __str__ in an exception instance

I'm trying to override the printed output from an Exception subclass in Python after the exception has been raised and I'm having no luck getting my override to actually be called. 我试图在引发异常后覆盖Python中Exception子类的打印输出,并且我没有运气实际调用我的覆盖。

def str_override(self):
    """
    Override the output with a fixed string
    """

    return "Override!"

def reraise(exception):
    """
    Re-raise an exception and override its output
    """

    exception.__str__ = types.MethodType(str_override, exception, type(exception))

    # Re-raise and remove ourselves from the stack trace.
    raise exception, None, sys.exc_info()[-1]

def test():
    """
    Should output "Override!" Actually outputs "Bah Humbug"
    """
    try:
        try:
            raise Exception("Bah Humbug")
        except Exception, e:
            reraise(e, "Said Scrooge")
    except Exception, e:
        print e

Any idea why this doesn't actually override the str method? 知道为什么这实际上没有覆盖str方法吗? Introspecting the instance variables shows that the method is actually overridden with the method but it's like Python just refuses to call it through print. 反思实例变量表明该方法实际上已被方法覆盖,但它就像Python一样拒绝通过print调用它。

What am I missing here? 我在这里错过了什么?

The problem is not that __str__() doesn't get overriden (just like you've already said, it does), but rather that str(e) (which invisibly gets called by print) is not always equivalent to e.__str__() . 问题不在于__str__()没有得到覆盖(就像你已经说过的那样),而是str(e) (通过print无形地调用) 并不总是等同于e.__str__() More specifically, if I get it right, str() (and other special methods, such as repr() ), won't look for str in the instance dictionary - it would only look for it in the class dictionary. 更具体地说,如果我说得对, str() (和其他特殊方法,如repr() )将不会在实例字典中查找str - 它只会在类字典中查找它。 At least that is the case for the so-called new-style classes (which are the only classes in Python 3.x IIRC). 至少对于所谓的新式类(这是Python 3.x IIRC中的唯一类)来说就是这种情况。 You can read more about it here: 你可以在这里读更多关于它的内容:

http://mail.python.org/pipermail/python-bugs-list/2005-December/031438.html http://mail.python.org/pipermail/python-bugs-list/2005-December/031438.html

If you want to change the exception error message for a reraised exception, you can do something like this instead: 如果要更改重新引发的异常的异常错误消息,可以执行以下操作:

def reraise(exception):
    """
    Re-raise an exception and override its output
    """

    exType = type(exception)
    newExType = type(exType.__name__ + "_Override", (exType,), { '__str__': str_override})
    exception.__class__ = newExType

    # Re-raise and remove ourselves from the stack trace.
    raise exception, None, sys.exc_info()[-1]

This will dynamically derive a new exception class with the str override, and change exception to be an instance of that class. 这将使用str覆盖动态派生新的异常类,并将异常更改为该类的实例。 Now your code should work. 现在你的代码应该工作了。

http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes states that "For new-style classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object's type, not in the object's instance dictionary". http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes声明“对于新式类,只保证特殊方法的隐式调用才能正常工作在对象的类型上定义,而不是在对象的实例字典中“。 IOW, you can't just assign a method to some_instance. __ str __ IOW,你不能只为some_instance. __ str __分配一个方法some_instance. __ str __ some_instance. __ str __ . some_instance. __ str __ Also, Monkey Patching will not work on builtin types like exceptions. 此外,Monkey Patching不适用于内置类型,例如异常。 Which you wouldn't want anyway, not even for a non-builtin exception class, since that patch would change the behaviour of all instances of that class. 你不会想要的,甚至不是非内置的异常类,因为该补丁会改变该类的所有实例的行为。

If you're feelin' kinda hackish you could instead do something like: 如果你觉得有点hackish,你可以做一些像:

...
except DaUncoolException, e:
    e.args = ('cool override stuff!',) + e.args[1:]
    raise

I don't like this very much, though. 不过,我不太喜欢这个。 Why would you want to do such a thing anyway? 你为什么要做这样的事呢?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM