为什么我能在Python中实例化我的抽象基类?

时间:2014-10-18 17:23:20

标签: python exception abstract-class python-3.4 abc

据我所知,我可以使用Python中的abc模块来创建无法实例化的抽象类(以及其他不错的属性)。我尝试使用它来创建Exception类的层次结构来表示我的应用程序的各种退出代码,但我仍然可以实例化我的基类,即使我不想要它发生。这里有一些代码可以证明这个问题:

#!/usr/bin/env python3

import abc

class ExitCodeException(Exception):
    __metaclass__ = abc.ABCMeta

    def __init__(self, message):
        super().__init__()
        self._message = message

    @abc.abstractmethod
    def getExitCode(self):
        """Return the exit code for this exception"""
        return

class FatalException(ExitCodeException):
    def getExitCode(self):
        return 1

raise ExitCodeException("Oh no!")

我期待我的程序退出,但有一个例外,即ExitCodeException无法实例化,而是我得到标准的堆栈跟踪,如果ExitCodeException没有&我#39;摘要:

Traceback (most recent call last)
  File "./email2pdf_classexception", line 21, in <module>
    raise ExitCodeException("Oh no!")
__main__.ExitCodeException

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

正如上面@BartoszKP和@Debanshu Kundu的评论中所讨论的那样,具体的超类Exception似乎是导致此问题的原因。因此,我提出了一个稍微不同的模式,似乎有效(据我所知,这是Python 2中较老式的模式,但似乎仍然有效):

#!/usr/bin/env python3

class ExitCodeException(Exception):
    def __new__(cls, *args, **kwargs):
        if cls is ExitCodeException:
            raise NotImplementedError("Base class may not be instantiated")
        return Exception.__new__(cls, *args, **kwargs)

    def __init__(self, message):
        super().__init__()
        self._message = message

    def getExitCode(self):
        """Return the exit code for this exception"""
        return

class FatalException(ExitCodeException):
    def getExitCode(self):
        return 1

raise FatalException("Oh no!")

这是按预期工作的;如果我将代码更改为直接实例化ExitCodeException,则会失败。