python中的鸭子类型,协议和接口
详谈Python中的鸭子类型,协议(不正式的接口)
这些天在搞javaweb,面向接口编程嘛,尤其玩spring的时候,在写接口的时候,脑海中总是浮现python,一想起还没有好好总结一下python中的鸭子类型,于是乎有了这边笔记。
一、python中协议和接口的区别
协议:被称作为“不正式的接口”,因为协议不像java的接口那样施加严格的规范
(java中的接口规范:关键要看子类是否是抽象类。
如果子类是非抽象类,则必须实现接口中的所有方法;
如果子类是抽象类,则可以不实现接口中的所有方法,因为抽象类中允许有抽象方法的存在。)
而协议可以不用只实现部分方法,同时,最重要的是协议和继承没有半毛钱关系哦!
这里先举一个简单的例子:
1 |
|
结果:
1 |
|
注:
由上面这个简单的例子我们可以发现,只要实现了__getitem__
方法,那么python解释器会将该类当做序列类即使没有继承也没有关系。这也就是鸭子类型的特征之一。同时,当类中没有实现__iter__
和__contain__
,解释器会设法让迭代和in运算符有效。
接下来,在举一个自定义的例子:
1 |
|
结果:
1 |
|
说明:可以看见,定义的Person,Monkey,Fisn
三个类之间并没有出现继承,但是都实现了相同的say方法,然后定义一个类似接口的函数interface
,只要实例满足存在say
方法就可以调用,而不会去检查这个animal
参数是不是特定类型的对象。
这就是鸭子类型的典型特征:不需要知道这个类对象是否是我们想要的对象,不需要继承,只要这个类对象,满足我们需要的方法,那么就可以执行其中相应的函数。
换言之就是只在乎其行为,不在乎其类型。
这也就是为什么编写类和方法的时候Python的参数不需要指明类型,而是通过鸭子类型的协议机制来判断传进来的对象是否满足我们所要求的行为!
最后谈一谈白鹅类型:
白鹅类型(针对抽象基类):只要cls是抽象类型,即cls的元类是abc.ABCMeta或者abc.ABC,就可以使用isinstance(obj,cls)。cls尽量用抽象基类,来增强其拓展性。对于某些抽象基类来说,有时只要子类实现了序列,那么抽象基类就可以把它作为自己的子类。原因在于抽象基类设定了一些权限,子类满足了这些权限,那么就成为抽象基类的子类。通过issubclass(obj,cls)来判断。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!