Python中的面向接口编程示例详解

 更新时间:2021年01月17日 11:04:27   作者:crossoverJie  
这篇文章主要给大家介绍了关于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)

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

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

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 时;虽然觉得语法啰嗦,但也会羡慕它的类型检查、参数验证这类特点。

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

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

到此这篇关于Python面向接口编程的文章就介绍到这了,更多相关Python面向接口编程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python中hash加密简介及使用方法

    Python中hash加密简介及使用方法

    常见 Hash 算法有 MD5 和 SHA 系列,目前 MD5 和 SHA1 已经被破解,一般推荐至少使用 SHA2-256 算法,接下来通过本文给大家介绍Python中hash加密简介及使用方法,感兴趣的朋友一起看看吧
    2022-01-01
  • Python实现以时间换空间的缓存替换算法

    Python实现以时间换空间的缓存替换算法

    缓存是指可以进行高速数据交换的存储器,它先于内存与CPU交换数据,因此速度很快。缓存就是把一些数据暂时存放于某些地方,可能是内存,也有可能硬盘。下面给大家介绍Python实现以时间换空间的缓存替换算法,需要的朋友参考下
    2016-02-02
  • python微信跳一跳系列之色块轮廓定位棋盘

    python微信跳一跳系列之色块轮廓定位棋盘

    这篇文章主要为大家详细介绍了python微信跳一跳系列,色块轮廓定位棋盘,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • pyinstaller打包后偶尔出现黑窗口一闪而过的问题及解决

    pyinstaller打包后偶尔出现黑窗口一闪而过的问题及解决

    这篇文章主要介绍了pyinstaller打包后偶尔出现黑窗口一闪而过的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Python中操作文件之write()方法的使用教程

    Python中操作文件之write()方法的使用教程

    这篇文章主要介绍了Python中操作文件之write()方法的使用教程,是Python入门学习中的基础知识,需要的朋友可以参考下
    2015-05-05
  • python elasticsearch从创建索引到写入数据的全过程

    python elasticsearch从创建索引到写入数据的全过程

    这篇文章主要介绍了python elasticsearch从创建索引到写入数据的方法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • numpy中np.sort返回索引的具体使用

    numpy中np.sort返回索引的具体使用

    本文主要介绍了使用numpy中np.sort函数返回索引的详细解释和使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Python hashlib常见摘要算法详解

    Python hashlib常见摘要算法详解

    这篇文章主要介绍了Python hashlib常见摘要算法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • python实现kmp算法的实例代码

    python实现kmp算法的实例代码

    这篇文章主要介绍了python实现kmp算法的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • pyside6-uic生成py代码中文为unicode(乱码)的问题解决方案

    pyside6-uic生成py代码中文为unicode(乱码)的问题解决方案

    这篇文章主要介绍了如何解决pyside6-uic生成py代码中文为unicode(乱码)的问题,文中通过代码和图文介绍的非常详细,对大家解决问题有一定的帮助,需要的朋友可以参考下
    2024-02-02

最新评论