【问题标题】:Python dynamic inheritance from ExceptionsPython 从异常中动态继承
【发布时间】:2016-05-28 13:47:11
【问题描述】:

我正在尝试创建一个可以从所有异常中继承的自定义异常。 我使用了一个包装器,这是我的代码:

def _MyError(_type, message=None, *args, **kwargs):
    class MyError(_type, object):
        def __init__(self, *_args, **_kwargs):
        super(MyError, self).__init__(self, message, *_args, **_kwargs)
        return

    return MyError(*args, **kwargs)


if(__name__ == '__main__'):
    try:
        raise _MyError(KeyError, message="ooops")
    except MyError as e:
        print "MyError occurred. ", e.message
    except BaseException:
        print "MyError not recognized.\n"

    try:
        raise _MyError(IndexError, message="ooops")
    except IndexError as e:
        print "MyError occurred. ", e.message
    except BaseException:
        print "MyError not recognized.\n"
    
    exit

输出:

MyError not recognized.
MyError not recognized.

建议?

【问题讨论】:

  • 您这样做是为了解决什么问题?

标签: python python-2.7 exception inheritance decorator


【解决方案1】:

这是一个相当棘手的问题。问题是您的专用 MyError 的创建失败并显示 IndexError。因为IndexError 不是KeyError,所以它会直接通过捕获它的尝试,而是作为BaseException 捕获。

def _MyError(_type, *args, **kwargs):
    class MyError(_type, object):
        def __init__(self, *_args, **_kwargs):
            super(MyError, self).__init__(self, *_args, **_kwargs)
            # Error on above line (IndexError from kwargs not accepted)

    return MyError(*args, **kwargs) # Error goes through here

try:
    raise _MyError(KeyError, message='hello')
    # raise never gets invoked, IndexError on calling _MyError
except KeyError: # IndexError != KeyError. This clause is skipped
    print 'KeyError'
# except BaseException: 
    # print 'BaseException'
# Commenting out the above lines will throw the error instead of catching it

您应该像这样创建错误:

raise _MyError(KeyError, 'hello')

【讨论】:

  • 检查代码...我试图将 _My(type, args) 捕获为 MyError,然后我尝试将其捕获为它的类型...
【解决方案2】:

Exceptions 不接受message;导致super(MyError, self).__init__(self, *_args, **_kwargs) 失败。

>>> IndexError(message='asdf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: exceptions.IndexError does not take keyword arguments

您需要将message 转换为位置参数:

def _MyError(_type, *args, **kwargs):
    class MyError(_type, object):
        def __init__(self, message=None):
            super(MyError, self).__init__(self, message)

    return MyError(*args, **kwargs)

【讨论】:

【解决方案3】:

当我在 Python 2.7 中尝试您的代码时,我收到以下错误:

Traceback (most recent call last):
  File "test.py", line 13, in <module>
    except MyError as e:
NameError: name 'MyError' is not defined

这并不奇怪,因为名称 MyError 在您尝试捕获它的文件级范围内不存在。

还要考虑每次调用_MyError() 函数时都在创建一个新类。因此,即使在except 块中 一个MyError 类可供使用,它也几乎肯定是错误 类(尽管名称相同)。

我怀疑您可能想要创建一个“根”MyError 类,然后在您的函数中创建一个 MyCustomError 类。然后,您可以在 exception 块中捕获 MyError(基)类并从那里继续。

编辑

根据您的评论,您可能可以执行以下操作:

class MyError:
    """Marker class for mixin."""
    pass

def my_error(_type, message=None, *args, **kwargs):
    class _MySubclass(_type, MyError):
        def __init__(self, *_args, **_kwargs):
            super(_MySubclass, self).__init__(message, *_args, **_kwargs)

    return _MySubclass(*args, **kwargs)

try:
    raise my_error(KeyError, message="key error")
except MyError as e:
    print "MyError occurred: ", e.message
except BaseException:
    print "Unknown error:", str(e)

try:
    raise my_error(IndexError, message="index error")
except MyError as e:
    print "MyError occurred: ", e.message
except BaseException:
    print "Unknown error:", str(e)

【讨论】:

  • 是的,我明白你的意思了......也可以像我尝试的那样只使用装饰器和直接捕获?
猜你喜欢
  • 2018-03-10
  • 2012-03-12
  • 2014-01-30
  • 2010-09-09
  • 2016-03-20
  • 1970-01-01
  • 2017-02-14
相关资源
最近更新 更多