Python是一种多态语言,其表现特征是:对象方法的调用方只管方法是否可调用,不管对象是什么类型,从而屏蔽不同类型对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

一、    Python中的协议

Python中定义某种类型是以实现了该类型对应的协议为标准的,如 可迭代对象(Iterable) 是指实现了可迭代协议的对象类型,迭代器是实现了迭代器协议的对象类型,序列是实现了序列协议的对象类型,那么具体协议是什么呢?在Python中协议是指一个或一组可供外部访问对象的特定方法(也有把对象属性作为协议的一部分,但老猿并不推荐这种使用方式),如可迭代对象是指容器中的元素可以通过__iter__( )方法或__getitem__( )方法访问,迭代器协议必须是定义和实现了__iter__()方法和next()方法,序列协议必须实现__len__()和getitem()方法。

协议是正式的,没有强制力,可以根据具体场景实现一个具体协议的一部分。例如,为了支持迭代,只需实现__getitem__,不需要实现__len__。

二、    “鸭子类型”与多态

从Python中协议的使用可以得出,Python中的对象类型不是简单的以类型定义区分的,而是以对象是否提供了特定的访问方法来确认的。凡是实现了类型要求的方法的对象都可以看做遵守类型对应协议,就是该类型的对象,老猿理解这是Python中多态的本质,这种以协议确认类型的方法所确认的类型就是“鸭子类型”(Duck typing)。

为什么说是“鸭子类型”呢?这个所有关于“鸭子类型”介绍的文章都有共同的介绍,在这复述一下:

鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。

鸭子类型这一名字出自美国James Whitcomb Riley(有的材料说他是诗人,有的说他是测试人员,在此就不探究了)提出的如下的表述:

“When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.”当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

简单归纳就是:对象的类型不再由继承等方式决定,而由实际运行时所表现出的具体行为来决定。

以下为定义的鸭子类型与人类型,它们都有相同的方法:

class Duck():

  def walk(self):

    print('I walk like a duck')

  def swim(self):

    print('I swim like a duck')

  def quack(self):

    print('I quack like a duck')

class Person():

  def walk(self):

    print('this one walk like a duck') 

  def swim(self):

    print('this man swim like a duck')

def quack(self):

    print('I quack like a duck')

类的定义语法在后面一节介绍,但大家应该明白上述两个类的定义。可以很明显的看出,Person类拥有跟Duck类一样的方法,当有一个函数调用Duck类,并利用到了三个方法walk()、swim()和quack()。我们传入Person类也一样可以运行,函数并不会检查对象的类型是不是Duck,只要他拥有这三个方法,就可以正确的被调用。

为什么Python的多态是由“鸭子类型”来实现呢?这是由于Python属于动态语言,Python在定义变量时不指定变量的类型,而是由解释器根据变量内容推断变量类型的(也就是说变量的类型取决于所关联的对象),因此Python在判断变量类型时是看变量所具有的功能(方法)来决定。这就造就了Python的这种非常神奇的多态和“鸭子类型”,也是开发者很喜欢的一种开放的程序开发风格。

三、    鸭子类型的优点

1.    python中的鸭子类型允许我们使用任何提供所需方法的对象,而不需要迫使它成为一个子类;

2.    因为任何提供正确接口的对象都可以在python中交替使用,它减少了多态的一般超类的需求。继承仍然可以用来共享代码,但是如果所有被共享的都是公共接口,鸭子类型就是所有所需的。这减少了继承的需要,同时也减少了多重继承的需要;

3.    调用方只管调用,不管细节,不管对象是什么类型,从而可以屏蔽不同类型对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

三、    鸭子类型编程的注意事项

1.    “鸭子类型”关注是对象的方法,而不是类型,因此使用Python开发时,尽量不要使用诸如type、issubclass等函数显式地执行类型检查进行类型检查;

2.    在进行方法调用时,对于程序无法明确确认对象是否有相应方法时,可以使用异常捕获或者hasattr或callable检查所需的方法是否存在来确保对应方法可以正常调用。如果有个对象p,我们需要判断p是否有swim方法,有如下方式:

1)    使用hasattr,语句:if hasattr(p,'swim') :p.swim()

2)    使用callable,语句:if hasattr(p,'swim')  and  callable(p.swim):p.swim()

3)    使用callable,语句:if  callable(getattr(p,'swim',None)):p.swim()

本节介绍了Python中协议和“鸭子类型”的概念,并说明了Python多态与“鸭子类型”的关系,同时分析了“鸭子类型”有点以及使用的注意事项。

老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用于逐步介绍老猿学习Python后总结的学习经验,这些经验有助于没有接触过Python的程序员可以很容易地进入Python的世界。

欢迎大家批评指正,谢谢大家关注!

第7.3节 Python特色的面向对象设计:协议、多态及鸭子类型的更多相关文章

  1. Python面向对象04 /封装、多态、鸭子类型、类的约束、super

    Python面向对象04 /封装.多态.鸭子类型.类的约束.super 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 3. 鸭子类型 4. 类的 ...

  2. python 面向对象专题(四):封装、多态、鸭子类型、类的约束、super

    https://www.cnblogs.com/liubing8/p/11321099.html 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 ...

  3. PythonI/O进阶学习笔记_3.1面向对象编程_python的多态和鸭子类型

    前言: 与第一篇的面向对象内容不同的是,第一篇中的面向对象更多的是与类.对象结合起来的概念粗浅理解,就是在编程历史中诞生的一种思想方法. 这篇的面向对象编程,更多落实到在语言设计实现中,是如何体现面向 ...

  4. Python面向对象----多态和鸭子类型

    1. C#中多态实现的条件是 继承, 重写以及父类指向子类. 但是在弱类型Python里面, 实现多态的条件就显得很简洁, 只需要在子类中实现父类相同名称的方法即可. 2. 鸭子类型的解释: 若一个类 ...

  5. python面向对象-封装-property-接口-抽象-鸭子类型-03

    封装 什么是封装: # 将复杂的丑陋的隐私的细节隐藏到内部,对外提供简单的使用接口 或 # 对外隐藏内部实现细节,并提供访问的接口 为什么需要封装 1.为了保证关键数据的安全性 2.对外部隐藏内部的实 ...

  6. python基础语法17 面向对象4 多态,抽象类,鸭子类型,绑定方法classmethod与staticmethod,isinstance与issubclass,反射

    多态 1.什么是多态? 多态指的是同一种类型的事物,不同的形态. 2.多态的目的: “多态” 也称之为 “多态性”,目的是为了 在不知道对象具体类型的情况下,统一对象调用方法的规范(比如:名字). 多 ...

  7. python学习-60 面向对象设计

    面向对象设计 1.三大编程范式 --面向过程编程 --函数式编程 --面向对象编程 2.编程进化论 --编程最开始就是无组织无结构,从简单控制流中按步写指令 --从上述的指令中提取重复的代码快或逻辑, ...

  8. python学习笔记-面向对象设计

    前言 1.三大编程范式: 面向过程编程 函数式编程 面向对象编程 2.编程进化论 1.编程最开始就是无组织无结构,从简单控制流中按步写指令 2.从上述的指令中提取重复的代码块或逻辑,组织到一起,便实现 ...

  9. Python多态、鸭子类型

    一.多态 多态指的是一类事物有多种形态. 动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.ab ...

随机推荐

  1. php ci下添加一个创建常用的模块和控制器方法

    我这么写是非常不好的 ,这些都可以写在lirbraries里面 (ci就是这么干的) 我这里是自己用 大概一个模型 没那么多讲究 现在core/CodeIgniter.php 文件 if($modle ...

  2. leetcode99:n-queens

    题目描述 N皇后问题是把N个皇后放在一个N×N棋盘上,使皇后之间不会互相攻击. 给出一个整数n,返回n皇后问题的所有摆放方案 例如: 4皇后问题有两种摆放方案 [".Q..",  ...

  3. 5 MVVM

    1.概述 MVVM各个部分功能如下: Model:定义业务逻辑 View:定义面向用户接口,UI逻辑,处理用户交互请求 ViewModel:负责界面导航逻辑和应用状态管理,呈现逻辑. 1.1. 各司其 ...

  4. java实现KFC点餐系统

    这篇文章主要为大家详细介绍了java实现KFC点餐系统,模拟肯德基快餐店的收银系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 同学们应该都去麦当劳或肯德基吃过快餐吧?请同学们参考肯德基官网的信 ...

  5. 知识全聚集 .Net Core 技术突破 | 简单说说工作单元

    知识全聚集 .Net Core 技术突破 | 简单说说工作单元 教程 01 | 模块化方案一 02 | 模块化方案二 其他教程预览 分库分表项目实战教程 Git地址: https://github.c ...

  6. Entity Fremework以及Fluentapi学习

    一.Entity Framework的入门  我这里采用的方式是数据库自己建立  然后模型类自己建立 数据库上下文类自己建立的方式 目的在于弄懂原理 其他的数据库优先等方式这里就不写了  教程有很多. ...

  7. 《.NET 5.0 背锅案》第4集:一个.NET,两手准备,一个issue,加倍关注

    第1集:验证 .NET 5.0 正式版 docker 镜像问题 第2集:码中的小窟窿,背后的大坑,发现重要嫌犯 EnyimMemcachedCore 第3集-剧情反转:EnyimMemcachedCo ...

  8. maven安装配置及其在IDEA和eclipse开发软件中配置

    1.maven下载安装 1.1.前往https://maven.apache.org/download.cgi下载最新版的Maven程序: 1.2.解压到本地,并配置环境变量 (1)path中添加 ( ...

  9. gcc入门(下)

    一 头文件与库文件(模块化,可重用,好维护)在使用C语言和其他语言进行程序设计的时候,我们需要头文件来提供对常数的定义和对系统以及库函数调用的声明库文件是一些预先编译好的函数的集合,那些函数都是按照可 ...

  10. exec系列函数详解

    execve替换进程映像(加载程序):execve系统调用,意味着代码段.数据段.堆栈段和PCB全部被替换.在UNIX中采用一种独特的方法,它将进程创建与加载一个新进程映像分离.这样的好处是有更多的余 ...