Python Tricks-- Abstract Base Classes Keep Inheritance in Check

简介: Python Tricks-- Abstract Base Classes Keep Inheritance in Check

Python Tricks-- Abstract Base Classes Keep Inheritance in Check
Abstract Base Classes(ABCs) ensure that derived classes implement particular methods from the base class. In this chapter you’ll learn about the benefits of abstract base classes and how to define them with Python’s built-in abc module.

So what are Abstract Base Classes good for? A while agao I had a discussion at work about which pattern to use for implementing a maintainable class hierarchy in Python. More specially, the goal was to define a simple class hierarchy for a service backend in the most programmer-friendly and maintainable way.

We had a BaseService class that defined a common interface and several concrete implementations. The concrete implementations do different things but all of them provide the same interface(MockService, RealService, and so on). To make this relationship explicit, the concrete implementations all subclass BaseService.

To make this code as maintainable and programmer-friendly as possible we wanted to make sure that:

Instantiating the base class is impossible; and
Forgetting to implement interface methods in one of the subclasses raises an error as early as possible.
Now why would you want to use Python’s abc module to solve this problem? The above design is pretty common in more complex systems. To enforce that a derived class implements a number of methods from the base class, something like this Python idiom is typically used:

[1]: class Base:
   ...:     def foo(self):
   ...:         raise NotImplementedError()
   ...:     def bar(self):
   ...:         raise NotImplementedError()

In [2]: class Concrete(Base):
   ...:     def foo(self):
   ...:         return 'foo() called'
   ...:     # Oh, no, we forgot to override bar()...
   ...:     # def bar(self):
   ...:     #    return "bar() called"
   ...:

So, what do we get from this first attempt at solving the problem?Calling methods on an instance of Base correctly raises NotImplementedError exceptions:

In [4]: b = Base()

In [5]: b.foo()
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)

Furthermore, instantiating and using Concrete works as expected. And, if we call an unimplemented method like bar() on it, this also raises an exception:

In [6]: c = Concrete()

In [7]: c.foo()
Out[7]: 'foo() called'

In [8]: c.bar()
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)

This first implementation is decent, but it isn’t perfect yet. The downsides here are that we can still:

  • Instantiate Base just fine without getting an error; and
  • Provide incomplete subclasses–instantiating Concrete will not raise an error until we call the missing method bar().

With Python’s abc module that was added in Python 2.6, we can do better and solve these remaining issues. Here’s an updated implementation using an Abstract Base Class defined with the abc module:

from abc import ABCMeta, abstractmethod

class Base(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass

    @abstractmethod
    def bar(self):
        pass
class Concrete(Base):
    def foo(self):
        pass
    # We forget to declare bar() again...

This still behaves as expected and creates the correct class hierarchy:

In [9]: assert issubclass(Concrete, Base)

Yet, we do get another very useful benefit here. Subclasses of Base raise a TypeError at instantiation time

TyperError:
"Can't instantiate abstract class Concrete with abstract methods bar"

Without abc, we’d only get a NotImplementedError if a missing method was actually called. Being notified about missing methods at instantiation time is a great advantage. It makes it more difficult to write invalid subclasses. This might not be a big deal if you’re writing new code, but a few weeks or months down the line, I promise it’ll be helpful.

This pattern is not a full replacement for compile-time type checking, of course. However, I found it often makes my class hierarchies more robust and more readily maintainable. Using ABCs states the programmer’s intent clearly and thus makes the code more communicative. I’d encourage you to read the abc module documentation and to keep an eye out for situations where applying this pattern makes sense.

相关文章
|
Ubuntu 计算机视觉 C++
Ubuntu系统下编译OpenCV4.8源码
通过上述步骤,你可以在Ubuntu系统上成功编译并安装OpenCV 4.8。这种方法不仅使你能够定制OpenCV的功能,还可以优化性能以满足特定需求。确保按照每一步进行操作,以避免常见的编译问题。
500 43
|
机器学习/深度学习 IDE 开发工具
基于OpenCV的车牌识别系统源码分享
基于OpenCV的车牌识别系统主要利用图像边缘和车牌颜色定位车牌,再利用OpenCV的SVM识别具体字符,从而达到车牌识别的效果。
668 4
基于OpenCV的车牌识别系统源码分享
写一个数据备份的脚本
请提供需要编写简介的具体内容,以便我为您完成任务。
ossutil cp 百万级别文件夹无反应
在处理文件夹上传时,小文件夹的上传过程顺畅无阻,但大文件夹的上传却会出现卡顿现象。
|
数据库连接 PHP 开发者
PHP中的魔术方法与它们的妙用
【10月更文挑战第2天】 在PHP编程中,魔术方法是一种特殊的方法,以双下划线(__)开头。它们为开发者提供了便捷的方式来管理类的行为,特别是在处理对象的初始化、序列化和克隆等方面。本文将介绍几个常见的魔术方法及其实际应用,助你在日常开发中游刃有余。
175 3
|
存储 JavaScript 数据库
云数据库的使用
云数据库的使用
156 0
acwing 173 矩阵距离
acwing 173 矩阵距离
118 0
【LeetCode 53】39.组合总和
【LeetCode 53】39.组合总和
193 0
Leetcode第十八题(四数之和)
这篇博客介绍了LeetCode第18题“四数之和”的解法,通过排序和双指针技术来找出数组中所有和为特定值的四个不同元素的组合。
182 0
|
15天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
5666 29
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考