简体   繁体   English

制作继承自Exception的抽象基类

[英]Making an abstract base class that inherits from Exception

I'm trying to create a custom base class for exceptions raised within my application. 我正在尝试为应用程序内引发的异常创建自定义基类。 I want to make it an abstract class (using the abc module) that cannot be directly instantiated, to force myself to define more specific concrete subclasses for different types of error situations. 我想使其成为不能直接实例化的抽象类(使用abc模块),以迫使自己针对不同类型的错误情况定义更具体的具体子类。

I can define an abstract class that inherits from a custom concrete class. 我可以定义一个继承自自定义具体类的抽象类。 However, to my surprise, if I make the abstract class inherit (directly or indirectly) from Exception, it can again be instantiated directly, defeating the purpose of making it abstract in the first place. 但是,令我惊讶的是,如果我使抽象类(直接或间接地)从Exception继承,则可以再次直接实例化它,从而破坏了首先使其抽象的目的。

I want to understand what's happening here so that I can make my custom exception class abstract for real and not directly instantiable. 我想了解这里发生的事情,以便可以将我的自定义异常类抽象为真正的实例,而不是直接实例化的实例。

I've tried different variations of declaring my custom exception class as abstract, including using the metaclass=abc.ABCMeta syntax as well as inheriting from abc.ABC . 我尝试了将我的自定义异常类声明为抽象的各种变体,包括使用metaclass=abc.ABCMeta语法以及从abc.ABC继承。 Regardless of the way it is declared as abstract, it ceases to behave like an abstract class as soon as I make it inherit from Exception . 无论将其声明为抽象的方式如何,只要我使它从Exception继承,它就会停止像抽象类一样工作。

Relevant Python versions for me are 3.5, 3.6 and 3.7. 对我而言,相关的Python版本是3.5、3.6和3.7。 I've tested the below code on Python 3.5.2 (Ubuntu 16.04) and 3.6.8 (Ubuntu 18.04). 我已经在Python 3.5.2(Ubuntu 16.04)和3.6.8(Ubuntu 18.04)上测试了以下代码。

The following seems to work as expected: instantiating AppException fails because of the abstract method ( TypeError: Can't instantiate abstract class AppException with abstract methods abs_method ). 以下内容似乎按预期方式工作:由于抽象方法而实例化AppException失败( TypeError: Can't instantiate abstract class AppException with abstract methods abs_method )。

Note that although the classes are called *Exception , they are not (yet) inheriting from the real built-in Exception class. 请注意,尽管这些类被称为*Exception ,但它们仍未从真正的内置Exception类继承。

import abc

class BaseException():
    pass

class AppException(BaseException, abc.ABC):

    @abc.abstractmethod
    def abs_method(self):
        pass

class ConcreteException(AppException):

    def abs_method(self):
        return "concrete method"

# BaseException can be instantiated just fine
a = BaseException()

# ConcreteException can be instantiated just fine
c = ConcreteException()

# It shouldn't be possible to instantiate AppException directly,
# so this line should raise a TypeError
b = AppException()

When I change the definition of BaseException to inherit from the actual Exception class: 当我更改BaseException的定义以从实际的Exception类继承时:

class BaseException(Exception):
    pass

then the TypeError goes away, so the instantiation of AppException did work this time. 然后TypeError消失了,因此AppException的实例化这次确实起作用了。 AppException is no longer behaving as an abstract class, even though in my understanding, it should. AppException不再表现为抽象类,即使按照我的理解,它也应该如此。

Here is the actual code , currently stuck as a draft PR until I can figure out what's going on. 这是实际的代码 ,目前停留在PR草案中,直到我弄清楚发生了什么。

This was covered earlier in this SO discussion . 这在本SO讨论的前面已经讨论过

There is no obvious solution, but one possible workaround (from the above SO discussion) is to add an __init__ method into the "abstract" extension class that prevents it from being instantiated directly. 没有明显的解决方案,但是一种可行的解决方法(来自上述SO讨论)是将__init__方法添加到“抽象”扩展类中,以防止直接实例化它。

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

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