Python 中的面向接口编程

简介: Python 中的面向接口编程

前言


”面向接口编程“Java 的朋友耳朵已经可以听出干茧了吧,当然这个思想在 Java 中非常重要,甚至几乎所有的编程语言都需要,毕竟程序具有良好的扩展性、维护性谁都不能拒绝。


最近无意间看到了我刚开始写 Python 时的部分代码,当时实现的需求有个很明显的特点:


  • 不同对象具有公共的行为能力,但具体每个对象的实现方式又各不相同。


说人话就是商户需要接入平台,接入的步骤相同,但具体实现不同。


作为一个”资深“ Javaer,需求还没看完我就洋洋洒洒的把各个实现类写好了:


网络异常,图片无法展示
|


当然最终也顺利实现需求,甚至把组里一个没写过 Java 的大哥唬的一愣一愣的,直呼牛逼。


不过事后也给我吐槽:


  • 你这设计是不错,但是感觉好复杂,跟代码时要找到真正的业务逻辑(实现类)得绕几圈。


截止目前 Python 写多了,我总算是能总结他的感受:就是不够 Pythonic


虽说 Python 没有类似 Java 这样的 Interface 特性,但作为面向对象的高级语言也是支持继承的;


在这里我们也可以利用继承的特性来实现面向接口编程:


class Car:
    def run(self):
        pass
class Benz(Car):
    def run(self):
        print("benz run")
class BMW(Car):
    def run(self):
        print("bwm run")
def run(car):
    car.run()
if __name__ == "__main__":
    benz = Benz()
    bmw = BMW()
    run(benz)
    run(bmw)


代码非常简单,在 Python 中也没有类似于 Java 中的 extends 关键字,只需要在类声明末尾用括号包含基类即可。


这样在每个子类中就能单独实现业务逻辑,方便扩展和维护。


类型检查


由于 Python 作为一个动态类型语言,无法做到 Java 那样在编译期间校验一个类是否完全实现了某个接口的所有方法。


为此 Python 提供了解决办法,那就是 abc(Abstract Base Classes) ,当我们将基类用 abc 声明时就能近似做到:


import abc
class Car(abc.ABC):
    @abc.abstractmethod
    def run(self):
        pass
class Benz(Car):
    def run(self):
        print("benz run")
class BMW(Car):
    pass
def run(car):
    car.run()
if __name__ == "__main__":
    benz = Benz()
    bmw = BMW()
    run(benz)
    run(bmw)


一旦有类没有实现方法时,运行期间便会抛出异常:


bmw = BMW()
TypeError: Can't instantiate abstract class BMW with abstract methods run


虽然无法做到在运行之前(毕竟不需要编译)进行校验,但有总比没有好。


鸭子类型


以上两种方式看似已经毕竟优雅的实现面向接口编程了,但实际上也不够 Pythonic

在继续之前我们先聊聊接口的本质到底是什么?


Java 这类静态语言中面向接口编程是比较麻烦的,也就是我们常说的子类向父类转型,因此需要编写额外的代码。


带来的好处也是显而易见,只需要父类便可运行。


但我们也不必过于执着于接口,它本身只是一个协议、规范,并不特指 Java 中的 Interface,甚至有些语言压根没有这个关键字。


动态语言的特性也不需要强制校验是否实现了方法。


Python 中我们可以利用鸭子类型来优雅的实现面向接口编程。


在这之前先了解下鸭子类型,借用维基百科的说法:


  • “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”


我用大白话翻译下就是:


即便两个完全不想干的类,如果他们都实现了相同的方法,那就可以把他们当做同一类型的类来使用。


举个简单例子:


class Order:
    def create(self):
        pass
class User:
    def create(self):
        pass
def create(obj):
    obj.create()
if __name__ == "__main__":
    order = Order()
    user = User()
    create(order)
    create(user)


这里的 orderuser 本身完全没有关系,只是他们都有相同方法,又得益于动态语言没法校验类型的特点,所以完全可以在运行的时候认为他们是同一种类型。


因此基于鸭子类型,之前的代码我们可以稍作简化:


class Car:
    def run(self):
        pass
class Benz:
    def run(self):
        print("benz run")
class BMW:
    def run(self):
        print("bwm run")
def run(car):
    car.run()
if __name__ == "__main__":
    benz = Benz()
    bmw = BMW()
    run(benz)
    run(bmw)


因为在鸭子类型中我们在意的是它的行为,而不是他们的类型;所以完全可以不用继承便可以实现面向接口编程。


总结


我觉得平时没有接触过动态类型语言的朋友,在了解完这些之后会发现新大陆,就像是 Python 老手第一次使用 Java 时;虽然觉得语法啰嗦,但也会羡慕它的类型检查、参数验证这类特点。


动静语言之争这里不做讨论了,各有各的好,鞋好不好穿只有自己知道。


随便提一下其实不止动态语言具备鸭子类型,有些静态语言也能玩这个骚操作,感兴趣下次再介绍。


相关文章
|
6天前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
20 3
|
8天前
|
开发者 Python
Python元类实战:打造你的专属编程魔法,让代码随心所欲变化
【7月更文挑战第7天】Python的元类是编程的变形师,用于创建类的“类”,赋予代码在构建时的变形能力。
30 1
|
9天前
|
设计模式 存储 Python
Python元类大揭秘:从理解到应用,一步步构建你的编程帝国
【7月更文挑战第6天】Python元类是创建类的对象的基石,允许控制类的生成过程。通过自定义元类,可在类定义时动态添加方法或改变行为。
16 0
|
6天前
|
数据采集 大数据 数据安全/隐私保护
Python编程:如何有效等待套接字的读取与关闭
Python网络编程中,套接字事件处理至关重要。利用`selectors`模块和代理IP能增强程序的稳定性和可靠性。代码示例展示了如何通过代理连接目标服务器,注册套接字的读写事件并高效处理。在代理IP配置、连接创建、事件循环及回调函数中,实现了数据收发与连接管理,有效应对网络爬虫或聊天应用的需求,同时保护了真实IP。
Python编程:如何有效等待套接字的读取与关闭
|
1天前
|
数据挖掘 开发者 Python
如何自学Python编程?
【7月更文挑战第14天】如何自学Python编程?
16 4
|
4天前
|
Python
不容错过!Python中图的精妙表示与高效遍历策略,提升你的编程艺术感
【7月更文挑战第11天】在Python编程中,图以邻接表或邻接矩阵表示,前者节省空间,后者利于查询连接。通过字典实现邻接表,二维列表构建邻接矩阵。图的遍历包括深度优先搜索(DFS)和广度优先搜索(BFS)。DFS使用递归,BFS借助队列。这些基础技巧对于解决复杂数据关系问题,如社交网络分析或迷宫求解,至关重要,能提升编程艺术。
13 5
|
6天前
|
存储 算法 Python
震撼!Python算法设计与分析,分治法、贪心、动态规划...这些经典算法如何改变你的编程世界!
【7月更文挑战第9天】在Python的算法天地,分治、贪心、动态规划三巨头揭示了解题的智慧。分治如归并排序,将大问题拆解为小部分解决;贪心算法以局部最优求全局,如Prim的最小生成树;动态规划通过存储子问题解避免重复计算,如斐波那契数列。掌握这些,将重塑你的编程思维,点亮技术之路。
14 1
|
8天前
|
程序员 Python
从零到一,彻底掌握Python闭包与装饰器的精髓,成为编程界的隐藏Boss
【7月更文挑战第7天】探索Python编程的两大基石:闭包与装饰器。闭包是内部函数记住外部作用域的变量,如`make_multiplier_of`返回的`multiplier`,它保持对`n`的引用。装饰器则是函数工厂,接收函数并返回新函数,如`my_decorator`,它在不改变原函数代码的情况下添加日志功能。掌握这些,让代码更优雅,效率更高,助你成为编程高手。
16 3
|
7天前
|
算法 索引 Python
Python算法设计与分析大揭秘:分治法、贪心算法、动态规划...掌握它们,让你的编程之路更加顺畅!
【7月更文挑战第8天】探索Python中的三大算法:分治(如快速排序)、贪心(活动选择)和动态规划(0-1背包问题)。分治法将问题分解求解再合并;贪心策略逐步求局部最优;动态规划通过记忆子问题解避免重复计算。掌握这些算法,提升编程效率与解决问题能力。
15 1
|
8天前
|
开发者 Python
元类,Python中的隐藏BOSS?掌握它,让你的编程之路畅通无阻
【7月更文挑战第7天】Python的元类是创建类的类,如同编程的“大BOSS”。它们让开发者在类创建时干预过程,添加功能,如自动注册、修改属性。元类通过`__new__`方法动态创建类,如示例中MetaClass得到Meta元类附加的属性。虽然使用需谨慎,以免增加复杂性,但元类提供了超越常规类的强大力量,解锁高级编程技术。
15 2