python支持接口编程吗,Python 中的面向接口编程

3b3cb362a75e451b87d74f4f.html

前言

”面向接口编程“写 Java 的朋友耳朵已经能够听出干茧了吧,固然这个思想在 Java 中很是重要,甚至几乎全部的编程语言都须要,毕竟程序具备良好的扩展性、维护性谁都不能拒绝。python

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

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

说人话就是商户须要接入平台,接入的步骤相同,但具体实现不一样。编程语言

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

3b3cb362a75e451b87d74f4f.html

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

3b3cb362a75e451b87d74f4f.html

不过过后也给我吐槽:code

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

截止目前 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 关键字,只须要在类声明末尾用括号包含基类便可。it

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

类型检查

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

动静语言之争这里不作讨论了,各有各的好,鞋好很差穿只有本身知道。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值