当前位置: 首页 > 科技观察

Python面向接口编程

时间:2023-03-17 13:14:02 科技观察

本文转载自微信公众号“crossoverJie”,作者crossoverJie。转载本文请联系crossoverJie公众号。前言《面向接口编程》写Java的朋友已经可以闻到茧了。当然这个思想在Java中非常重要,甚至几乎所有的编程语言都需要它。毕竟程序具有很好的扩展性和可维护性。无法拒绝。最近刚开始写Python的时候无意中看到了部分代码。当时的实现需求有一个明显的特点:不同的对象具有共同的行为能力,但每个对象的具体实现方式不同。也就是说,商家需要接入平台,接入的步骤是一样的,只是具体实现方式不同。作为一个“资深”的Javaer,在看需求之前就把所有的实现类都写的洋洋洒洒的:当然,最后还是成功实现了需求,连群里一个没写过Java的大哥都愣了一下.称其为真棒。但是事后也跟我吐槽:你的设计不错,就是感觉很复杂。跟着代码走,要绕几圈才能找到真正的业务逻辑(实现类)。到目前为止,我已经写了很多Python,我终于可以总结一下他的感受:不够Pythonic。Python虽然没有Java那样的Interface特性,但是作为一种面向对象的高级语言,它也支持继承;这里我们也可以利用继承特性来实现面向接口的编程:"bwmrun")defrun(car):car.run()if__name__=="__main__":benz=Benz()bmw=BMW()run(benz)run(bmw)的代码很简单,没有Python中的extends关键字类似于Java中的关键字。您只需要在类声明的末尾用括号将基类括起来。这样可以在每个子类中独立实现业务逻辑,方便扩展和维护。类型检查由于Python是一种动态类型的语言,因此无法像Java那样在编译时验证一个类是否完全实现了接口的所有方法。Python为此提供了一种解决方案,即abc(AbstractBaseClasses),当我们用abc声明基类时,我们可以近似:importabcclassCar(abc.ABC):@abc.abstractmethoddefrun(self):passclassBenz(Car):defrun(self):print("benzrun")classBMW(Car):passdefrun(car):car.run()if__name__=="__main__":benz=Benz()bmw=BMW()run(benz)run(bmw)一旦一个类没有实现某个方法,运行时会抛出异常:bmw=BMW()TypeError:Can'instantiateabstractclassBMWwithabstractmethodsrun虽然无法在运行前验证(毕竟不需要编译),但总比不好。以上两种ducktyping的方法,看似优雅地实现了面向接口编程,但实际上还不够Pythonic。在继续之前,让我们谈谈接口的本质。Java等静态语言的面向接口编程比较麻烦,也就是我们常说的子类转化为父类,需要额外写代码。好处也很明显,只需要父类就可以运行。不过我们也不必太迷恋接口,它本身只是一种协议,一种规范,并没有特指Java中的Interface,甚至有些语言根本就没有这个关键字.动态语言的特性不需要强制验证方法是否实现。在Python中,我们可以使用鸭子类型来优雅地实现面向接口的编程。在此之前,我们先了解一下鸭子的类型,借用维基百科:“当你看到一只鸟走路像鸭子,游泳像鸭子,叫声像鸭子,那么这只鸟就可以称为鸭子。”我用大白话翻译就是:即使两个根本不想做的类,如果都实现了同一个方法,也可以作为同类型的类。一个简单的例子:classOrder:defcreate(self):passclassUser:defcreate(self):passdefcreate(obj):obj.create()if__name__=="__main__":order=Order()user=User()create(order)的create(user)中这里的order和用户本身没有关系,但是他们都有相同的方法,而且由于动态语言无法验证类型,所以在运行时可以认为它们是同一个类型。所以在duck类型的基础上,我们可以稍微简化一下前面的代码:(car):car.run()if__name__=="__main__":benz=Benz()bmw=BMW()run(benz)run(bmw)因为在ducktyping中我们关心它的行为,而不是它们的类型;所以面向接口编程可以不用继承来实现。综上所述,我想没有接触过动态类型语言的朋友,了解了这些,就会发现新大陆,就像Python老手第一次使用Java时一样;虽然他们觉得语法啰嗦,但他们也会羡慕它的类型检查和参数验证。这样的功能。静态语言和口头语言的争论这里就不展开讨论了,各有千秋,鞋子好不好只有自己知道。顺便提一下,不仅动态语言有duck类型,一些静态语言也可以玩这个花哨的操作。如果大家有兴趣,下次再介绍。