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


Posted in Python onJanuary 17, 2021

前言

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

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

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

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

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

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

当然最终也顺利实现需求,甚至把组里一个没写过 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 时;虽然觉得语法??拢??不嵯勰剿?睦嘈图觳椤⒉问?橹ふ饫嗵氐恪?/p>

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

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

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

Python 相关文章推荐
python实现的一个火车票转让信息采集器
Jul 09 Python
Python增量循环删除MySQL表数据的方法
Sep 23 Python
python cx_Oracle模块的安装和使用详细介绍
Feb 13 Python
Python处理Excel文件实例代码
Jun 20 Python
python发送邮件脚本
May 22 Python
python读取word文档,插入mysql数据库的示例代码
Nov 07 Python
python画柱状图--不同颜色并显示数值的方法
Dec 13 Python
简单了解django orm中介模型
Jul 30 Python
python 用 xlwings 库 生成图表的操作方法
Dec 22 Python
浅谈SciPy中的optimize.minimize实现受限优化问题
Feb 29 Python
python利用文件时间批量重命名照片和视频
Feb 09 Python
Django利用AJAX技术实现博文实时搜索
May 06 Python
Python学习之time模块的基本使用
Jan 17 #Python
python中re模块知识点总结
Jan 17 #Python
史上最详细的Python打包成exe文件教程
Jan 17 #Python
python制作微博图片爬取工具
Jan 16 #Python
python工具——Mimesis的简单使用教程
Jan 16 #Python
Python 内存管理机制全面分析
Jan 16 #Python
python des,aes,rsa加解密的实现
Jan 16 #Python
You might like
PHP XML备份Mysql数据库
2009/05/27 PHP
浅析PHP 按位与或 (^ 、&)
2013/06/21 PHP
PHP+swoole实现简单多人在线聊天群发
2016/01/19 PHP
php多线程并发实现方法
2016/09/30 PHP
PHP解压ZIP文件到指定文件夹的方法
2016/11/17 PHP
Zend Framework入门教程之Zend_Mail用法示例
2016/12/08 PHP
浅析PHP中的闭包和匿名函数
2017/12/25 PHP
js 上传图片预览问题
2010/12/06 Javascript
javascript 日期时间 转换的方法
2013/02/21 Javascript
JavaScript中string对象
2015/06/12 Javascript
jQuery实现仿QQ在线客服效果的滚动层代码
2015/10/15 Javascript
JavaScript生成二维码图片小结
2015/12/27 Javascript
利用Angularjs和原生JS分别实现动态效果的输入框
2016/09/01 Javascript
swiper移动端轮播插件(触碰图片之后停止轮播)
2017/12/28 Javascript
最后说说Vue2 SSR 的 Cookies 问题
2018/05/25 Javascript
vue代理和跨域问题的解决
2018/07/18 Javascript
vue中@change兼容问题详解
2019/10/25 Javascript
Vue移动端项目实现使用手机预览调试操作
2020/07/18 Javascript
Vue之封装公用变量以及实现方式
2020/07/31 Javascript
python发腾讯微博代码分享
2014/01/10 Python
python高手之路python处理excel文件(方法汇总)
2016/01/07 Python
pandas的连接函数concat()函数的具体使用方法
2019/07/09 Python
如何使用PyCharm将代码上传到GitHub上(图文详解)
2020/04/27 Python
Python控制台实现交互式环境执行
2020/06/09 Python
python切割图片的示例
2020/11/12 Python
HTML5的结构和语义(1):前言
2008/10/17 HTML / CSS
在数据文件自动增长时,自动增长是否会阻塞对文件的更新
2014/05/01 面试题
应聘收银员个人的求职信
2013/11/30 职场文书
乡镇消防工作实施方案
2014/03/27 职场文书
地质灾害防治方案
2014/05/14 职场文书
三孔导游词
2015/02/05 职场文书
2015年税务稽查工作总结
2015/05/26 职场文书
同事欢送会致辞
2015/07/31 职场文书
离职告别感言
2015/08/04 职场文书
社区宣传标语口号
2015/12/26 职场文书
化工生产实习心得体会
2016/01/22 职场文书