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 相关文章推荐
用map函数来完成Python并行任务的简单示例
Apr 02 Python
Python的Flask框架应用调用Redis队列数据的方法
Jun 06 Python
python实现字典(dict)和字符串(string)的相互转换方法
Mar 01 Python
Python内建函数之raw_input()与input()代码解析
Oct 26 Python
Python实现在某个数组中查找一个值的算法示例
Jun 27 Python
Flask实现图片的上传、下载及展示示例代码
Aug 03 Python
python3使用腾讯企业邮箱发送邮件的实例
Jun 28 Python
PyTorch: 梯度下降及反向传播的实例详解
Aug 20 Python
scikit-learn线性回归,多元回归,多项式回归的实现
Aug 29 Python
Python selenium 加载并保存QQ群成员,去除其群主、管理员信息的示例代码
May 28 Python
Python xlrd/xlwt 创建excel文件及常用操作
Sep 24 Python
Matplotlib可视化之添加让统计图变得简单易懂的注释
Jun 11 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 引用(&)详解
2009/11/20 PHP
wamp安装后自定义配置的方法
2014/08/23 PHP
php获取根域名方法汇总
2014/10/28 PHP
值得分享的php+ajax实时聊天室
2016/07/20 PHP
thinkphp jquery实现图片上传和预览效果
2020/07/22 PHP
php文件上传及下载附带显示文件及目录功能
2017/04/27 PHP
Javascript中产生固定结果的函数优化技巧
2013/01/16 Javascript
构造函数+原型模式构造js自定义对象(最通用)
2014/05/12 Javascript
封装了jQuery的Ajax请求全局配置
2015/02/05 Javascript
Node.js 学习笔记之简介、安装及配置
2015/03/03 Javascript
谈谈基于iframe、FormData、FileReader三种无刷新上传文件的方法
2015/12/03 Javascript
jquery插件autocomplete用法示例
2016/07/01 Javascript
详解JS对象封装的常用方式
2016/12/30 Javascript
angularjs实现多张图片上传并预览功能
2017/02/24 Javascript
javascript使用btoa和atob来进行Base64转码和解码
2017/03/20 Javascript
node.js多个异步过程中判断执行是否完成的解决方案
2017/12/10 Javascript
微信小程序实现点击图片放大预览
2019/10/21 Javascript
js实现双色球效果
2020/08/02 Javascript
详解appium+python 启动一个app步骤
2017/12/20 Python
python微信跳一跳系列之棋子定位像素遍历
2018/02/26 Python
python操作excel的方法
2018/08/16 Python
检测python爬虫时是否代理ip伪装成功的方法
2019/07/12 Python
Python 中@property的用法详解
2020/01/15 Python
Python编写memcached启动脚本代码实例
2020/08/14 Python
Spy++的使用方法及下载教程
2021/01/29 Python
亚马逊西班牙购物网站:amazon西班牙
2017/03/06 全球购物
建筑工程技术应届生求职信
2013/11/17 职场文书
电脑教师的自我评价
2013/12/18 职场文书
房地产融资计划书
2014/01/10 职场文书
2014年派出所工作总结
2014/11/21 职场文书
装修公司管理制度
2015/08/05 职场文书
校园广播稿范文
2015/08/19 职场文书
详解TypeScript中的类型保护
2021/04/29 Javascript
css3属性选择器 “~”(波浪号) “,”(逗号) “+”(加号)和 “>”(大于号)
2022/04/19 HTML / CSS
Python探索生命起源 matplotlib细胞自动机动画演示
2022/04/21 Python
Python3使用Qt5来实现简易的五子棋小游戏
2022/05/02 Python