首页 > 解决方案 > 异常 str() 失败 - py3

问题描述

这在 Py2 中工作正常,但在 Py3 中失败

import sys

class MyBaseError(Exception):
    def __init__(self, message, base_message=None, *args):
        
        self.base_message = base_message
        super(MyBaseError, self).__init__(message)
        
        
    def __str__(self):
        if self.base_message is None:
            return self.message
        
        return self.message + " '" + str(self.base_message) + "'"
        
        
class MyError(MyBaseError):
    """
    """
    
class MyTypeError(MyError):
    """
    """

def run_me():
    raise MyTypeError("run_me")
    

def sayonara():
    try:
        run_me()
    except (MyBaseError) as e:
        raise(MyBaseError("unable to run",
                           e,
                           e.args),
                sys.exc_info()[2])
                
sayonara()

在 Py2 我得到

Traceback (most recent call last):
  File "main.py", line 39, in <module>
    sayonara()
  File "main.py", line 37, in sayonara
    sys.exc_info()[2])
__main__.MyBaseError: unable to run 'run_me'

在 Py3 我得到

Traceback (most recent call last):
  File "main.py", line 32, in sayonara
    run_me()
  File "main.py", line 27, in run_me
    raise MyTypeError("run_me")
__main__.MyTypeError: <exception str() failed>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "main.py", line 42, in <module>
    sayonara()
  File "main.py", line 34, in sayonara
    print(e)
  File "main.py", line 13, in __str__
    return self.message
AttributeError: 'MyTypeError' object has no attribute 'message'

你能建议我怎么做这个多语种吗?

标签: pythonpython-3.x

解决方案


__str__您在 MyBaseError 中定义的实例方法的覆盖实现引用了不存在的实例变量。 message在构造函数的签名中声明的参数message具有本地范围

当您将字符串等不可变参数传递给函数时,会传递参数的值。在MyBaseError您的构造函数中,将局部变量的值传递message给代理对象的__init__方法,代理对象将方法调用委托给父类Exception

在 python3 中,Exception没有定义一个实例变量message来保存实例参数的字符串表示形式。这就是导致异常的原因。

此外,如果您解决了该问题,您将收到类型错误:

TypeError: exceptions must derive from BaseException

那是因为你写的 raise 语句不符合 Python 3 中 raise 语句的语义。 raise 语句的 BNF 如下所示:

raise_stmt ::=  "raise" [expression ["from" expression]]

正如语言参考所述:'raise 将第一个表达式评估为异常对象。它必须是 BaseException 的子类或实例。

但是,在您的 raise 语句中,第一个表达式是一个元组:

(MyBaseError("unable to run", e, e.args), sys.exc_info()[2])

https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement)。

要修复您的代码,请创建message一个实例变量并重构 raise 语句。

import sys


class MyBaseError(Exception):
    def __init__(self, message, base_message=None, *args):
        self.base_message = base_message
        self.message = message

    def __str__(self):
        if self.base_message is None:
            return self.message

        return self.message + " '" + str(self.base_message) + "'"


class MyError(MyBaseError):
    """
    """


class MyTypeError(MyError):
    """
    """


def run_me():
    raise MyTypeError("run_me")


def sayonara():
    try:
        run_me()
    except (MyBaseError) as e:
        raise MyBaseError("unable to run", e, e.args)


sayonara()

此外,以下语句从您的代码中返回一个回溯对象。

sys.exc_info()[2]

正如语言参考所述:“当引发异常并将其作为可写的回溯属性附加到它时,通常会自动创建回溯对象。” 如果您愿意,您可以使用 with_traceback() 异常方法一步设置您自己的自定义回溯。


推荐阅读