浅析Python中接口与抽象基类的使用

 更新时间:2024年12月15日 08:24:39   作者:databook  
这篇文章主要为大家详细介绍了Python中两个为面向对象编程提供的强大工具接口和抽象基类的使用,感兴趣的小伙伴可以跟随小编一起学习一下

接触Python比较早的朋友可能都有这样的体会,Python语言虽然也支持面向对象的编程方式,

但是,不像那些纯面向对象的语言(比如Java.NET)那样严格和规范。

随着项目的规模逐步扩大之后,想要以一种清晰、可维护和可扩展的方式定义和实施对象的行为就变得越来越困难。

今天介绍的Python中两个为面向对象编程提供的强大工具:接口抽象基类

它们的英文分别为ProtocolsABC(Abstract Base Classes)。

ProtocolsPython3.8才开始引入的,有的地方也翻译成协议,我感觉翻译成接口更熟悉一些。

ABC引入的比较早,在Python3之后得到了改进和优化,现在和其他语言的抽象类相比,差别不大。

1. 接口(Protocols)

Python3.8开始在类型模块中引入的接口Protocols的概念,它提供了一种无需显式继承即可定义接口的方法。

接口Protocols定义了一组方法或属性,只要一个对象实现了这些方法或属性,就被视为满足该接口。

下面通过一个示例来帮助理解Protocols的使用,如果有面向对象编程的经验,很容易就能理解这个概念。

这个示例来自最近用的一个量化交易系统的一部分,这个功能需要从不同的来源获取数据,然后进行分析,最后将分析结果以不同的方式输出

这三个步骤(获取数据,分析和输出)中,

假设获取数据的来源有网络(API),文件(CSV)和数据库3种;

分析的步骤是统一的;输出的方式假设也有多种,比如邮件,短信等等。

根据这个描述,使用Protocols构建的获取数据和分析部分的代码如下:

输出的部分暂时不管

from typing import Protocol


# 输入数据的接口
class InputData(Protocol):
    def get_data(self) -> str:
        pass


class APIHandler:
    def get_data(self) -> str:
        print("get_data from API")
        return "get data from API"


class CSVHandler:
    def get_data(self) -> str:
        print("get_data from CSV")
        return "get data from CSV"


class SqliteHandler:
    def get_data(self) -> str:
        print("get_data from SQLITE DATABASE")
        return "get data from SQLITE DATABASE"


# 分析数据
def analysis(i: InputData):
    data = i.get_data()

    print("开始处理数据...")

InputData继承了Protocol,其中定义了接口的函数get_data

只要实现了get_dataclass,比如APIHandlerCSVHandlerSqliteHandler,都可以当做InputData类型。

从代码可以看出,我们不需要用APIHandler去继承InputData,只要实现InputData中的所有方法就可以了。

这种灵活性确保了系统的可扩展性,我们可以添加新的数据源类型,而无需修改现有代码。

接下来我们测试上面的代码是否可以正常使用:

if __name__ == "__main__":
    i = APIHandler()
    analysis(i)
    print("\n")

    i = CSVHandler()
    analysis(i)
    print("\n")

    i = SqliteHandler()
    analysis(i)
    print("\n")

运行结果:

$  python.exe .\protocol_abc.py
get_data from API
开始处理数据...

get_data from CSV
开始处理数据...

get_data from SQLITE DATABASE
开始处理数据...

2. 抽象基类(ABC)

Protocol非常具有灵活性,但有时我们需要更结构化的方法,这就是抽象基类 (ABC) 的用武之地。

ABC 是一种通过定义子类必须实现的严格接口来强制执行一致行为的工具。

Protocol不同,ABC 需要显式继承,因此当我们希望在代码中明确定义层次结构时,ABC是更好的选择。

接着实现上一节示例中的输出部分,每种不同的输出需要不同的配置,

比如输出到邮件需要先配置邮箱的账号信息,输出到短信需要配置手机信息等等。

在这里,我们使用 ABC 来实现输出的基类。

# 输出的抽象基类
class OutputResult(ABC):
    def __init__(self):
        self.settings: dict = {}

    @abstractmethod
    def send(self, data: str):
        pass

    @abstractmethod
    def config(self, settings: dict):
        pass


class OutputMail(ABC):
    def send(self, data: str):
        print(f"send {data} to {self.settings['name']}")

    def config(self, settings: dict):
        self.settings = settings


class OutputMessage(ABC):
    def send(self, data: str):
        print(f"send {data} to {self.settings['name']}")

    def config(self, settings: dict):
        self.settings = settings

这里使用抽象基类的原因是输出时,并不是简单的调用send方法就可以的,还需要配置输出的参数,

所以用带有结构的抽象基类更好。

加上输出之后,上一节中的分析函数也改为:

# 分析数据
def analysis(i: InputData, o: OutputResult):
    data = i.get_data()

    print("开始处理数据...")
    data = data.replace("get data from ", "")

    o.send(data)

测试的代码如下:

if __name__ == "__main__":
    i = APIHandler()
    o = OutputMail()
    o.config({"name": "aaa@bbb.com"})
    analysis(i, o)
    print("\n")

    i = CSVHandler()
    o = OutputMessage()
    o.config({"name": "13911123456"})
    analysis(i, o)
    print("\n")

    i = SqliteHandler()
    o = OutputMail()
    o.config({"name": "xyz@www.com"})
    analysis(i, o)
    print("\n")

运行结果:

$  python.exe .\protocol_abc.py
get_data from API
开始处理数据...
send API to aaa@bbb.com

get_data from CSV
开始处理数据...
send CSV to 13911123456

get_data from SQLITE DATABASE
开始处理数据...
send SQLITE DATABASE to xyz@www.com

3. 两者的选择

当我们在实际的开发设计中,应该如何选择ProtocolABC呢?

其实,ProtocolABC之间的选择并不是非黑即白,这通常取决于项目的背景和你的目标。

一般来说,下面这些情况我们优先选择使用Protocol

  • 你正在使用现有代码或希望集成第三方库
  • 灵活性是首要任务,你不想强制执行严格的层次结构
  • 来自不相关的类层次结构的对象需要共享行为

而下面这些情况,优先选择ABC

  • 正在从头开始设计一个系统,并且需要加强结构
  • 类之间的关系是可预测的,并且继承是有意义的
  • 共享功能或默认行为可以减少重复并提高一致性

4. 总结

总的来说,ProtocolABC不是互相竞争的两种工具,它们是互补的。

我使用Protocol将类型安全改造到遗留系统中,而不需要大量重构。

另一方面,如果我在从头开始构建一个结构和一致性至关重要的系统时,会使用 ABC

在决定使用哪个时,请考虑项目的灵活性需求和长期目标。

Protocol提供灵活性和无缝集成,而 ABC 有助于建立结构和一致性。

通过了解它们各自的优势,你可以选择合适的方式来构建健壮、可维护的 Python 系统。

到此这篇关于浅析Python中接口与抽象基类的使用的文章就介绍到这了,更多相关Python接口与抽象基类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python使用udp实现聊天器功能

    python使用udp实现聊天器功能

    这篇文章主要介绍了python使用udp实现聊天器功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2018-12-12
  • 利用python实现简易版的贪吃蛇游戏(面向python小白)

    利用python实现简易版的贪吃蛇游戏(面向python小白)

    这篇文章主要给大家介绍了关于如何利用python实现简易版的贪吃蛇游戏的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • Python2和Python3的共存和切换使用

    Python2和Python3的共存和切换使用

    这篇文章主要介绍了Python2和Python3的共存和切换使用,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • 浅谈Python 中的复数问题

    浅谈Python 中的复数问题

    这篇文章主要介绍了在Python 中的复数问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • python实现单线程多任务非阻塞TCP服务端

    python实现单线程多任务非阻塞TCP服务端

    这篇文章主要为大家详细介绍了python实现单线程多任务非阻塞TCP服务端的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • Python 使用pandas实现查询和统计示例详解

    Python 使用pandas实现查询和统计示例详解

    这篇文章主要为大家介绍了Python 使用pandas实现查询和统计示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • 详解python持久化文件读写

    详解python持久化文件读写

    这篇文章主要介绍了python持久化文件读写,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • python检测lvs real server状态

    python检测lvs real server状态

    这篇文章主要介绍了用python检测lvs real server状态的示例,大家参考使用吧
    2014-01-01
  • python如何调用现有的matlab函数

    python如何调用现有的matlab函数

    这篇文章主要介绍了python如何调用现有的matlab函数问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • django使用admin站点上传图片的实例

    django使用admin站点上传图片的实例

    今天小编就为大家分享一篇django使用admin站点上传图片的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07

最新评论