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搭建微信公众平台
Feb 09 Python
利用python发送和接收邮件
Sep 27 Python
TF-IDF算法解析与Python实现方法详解
Nov 16 Python
Pycharm设置界面全黑的方法
May 23 Python
Python读取英文文件并记录每个单词出现次数后降序输出示例
Jun 28 Python
Python实现打砖块小游戏代码实例
May 18 Python
Pandas中resample方法详解
Jul 02 Python
Python urllib.request对象案例解析
May 11 Python
django Model层常用验证器及自定义验证器详解
Jul 15 Python
基于Python3读写INI配置文件过程解析
Jul 23 Python
OpenCV+Python3.5 简易手势识别的实现
Dec 21 Python
Python实现查询剪贴板自动匹配信息的思路详解
Jul 09 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项目中百度 UEditor 简单安装调试和调用
2015/07/15 PHP
smarty高级特性之对象的使用方法
2015/12/25 PHP
laravel解决迁移文件一次删除创建字段报错的问题
2019/10/24 PHP
PHP数组Key强制类型转换实现原理解析
2020/09/01 PHP
Extjs中常用表单介绍与应用
2010/06/07 Javascript
基于jquery的多功能软键盘插件
2012/07/25 Javascript
javascript克隆对象深度介绍
2012/11/20 Javascript
THREE.JS入门教程(5)你应当知道的十件事
2013/01/24 Javascript
JS实现图片放大镜效果的方法
2015/02/27 Javascript
Javascript中的getUTCDay()方法使用详解
2015/06/10 Javascript
使用JQuery选择HTML遍历函数的方法
2016/09/17 Javascript
AngularJS页面传参的5种方式
2017/04/01 Javascript
import与export在node.js中的使用详解
2017/09/28 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
使用jquery-easyui的布局layout写后台管理页面的代码详解
2019/06/19 jQuery
elementui之el-tebs浏览器卡死的问题和使用报错未注册问题
2019/07/06 Javascript
js数据类型转换与流程控制操作实例分析
2019/12/18 Javascript
JS浏览器BOM常见操作实例详解
2020/04/27 Javascript
vue 单页应用和多页应用的优劣
2020/10/22 Javascript
[00:32]10月24、25日 辉夜杯外卡赛附加赛开赛!
2015/10/23 DOTA
python使用mailbox打印电子邮件的方法
2015/04/30 Python
Python解析命令行读取参数--argparse模块使用方法
2018/01/23 Python
Flask框架学习笔记之模板操作实例详解
2019/08/15 Python
python之pygame模块实现飞机大战完整代码
2020/11/29 Python
CSS3动画和HTML5新特性详解
2020/08/31 HTML / CSS
移动端html5判断是否滚动到底部并且下拉加载
2019/11/19 HTML / CSS
VICHY薇姿美国官方网站:欧洲药房第一的抗衰老品牌
2017/11/22 全球购物
Sisley法国希思黎中国官网:享誉全球的奢华植物美容品牌
2019/06/30 全球购物
三年大学自我鉴定
2014/01/16 职场文书
2014年公司庆元旦活动方案
2014/03/05 职场文书
《她是我的朋友》教学反思
2014/04/26 职场文书
我有一个梦想演讲稿
2014/05/05 职场文书
2015年入党决心书
2015/02/05 职场文书
男方家长婚礼答谢词
2015/09/29 职场文书
师德师风心得体会(2016精选篇)
2016/01/12 职场文书
Win11运行育碧游戏总是崩溃怎么办 win11玩育碧游戏出现性能崩溃的解决办法
2022/04/06 数码科技