面向对象之(多态)

一.面向对象简介。
在面向对象程序设计中,术语对象(object)基本上可以看做数据(特性)以及由一系列可以存取,操作这些数据的方法所组成的集合。使用对象替代全局变量和函数的原因可能有很多。其中对象最重要的优点包括以下几个方面。
1.多态(Polymorphism):意味着可以对不同类的对象使用同样的操作,它们会像被“施了魔法一般”工作。
2.封装(Encapsulation):对外部世界隐藏对象的工作细节。
3.继承(Inheritance):以通用的类为基础建立专门的类对象。
二.1.多态
多态意思是“有多种形式”。多态意味着就算不知道变量所引用的对象类型是什么,还是能对它进行操作,而它也会根据对象(或类)类型的不同而表现出不同的行为。——————多态,是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

例如,假设一个食品销售的商业网站创建了一个在线支付系统。程序会从系统的其他部分(或者以后可能会设计的其他类型的系统)获得一“购物车”中的商品,接下来要做的就是算出总价然后使用信用卡支付。
当你的程序获得商品时,首先想到的可能是如何具体地表示它们。比如需要将它们作为元组接收,像下面这样:

>>>('SPAM',2.50)

如果需要描述性标签和价格,这样就够了,但是这个程序还是不够灵活。我们假设网站支持拍卖服务,价格在货物卖出之前会逐渐降低。如果用户能把对象放入购物车,然后处理结账(你的系统部分),等价格到了满意的程度后按下“支付”按钮就好了。
但是这样一来简单的元组就不能满足需要了。为了实现这个功能,代码每次询问价格的时候,对象都需要检查当前的价格(通过网络的某些功能),价格不能固定在元组中。解决起来不难,只要写个函数:

#不要这样做
>>>def getPrice(object):
>>>    if isinstance(object,tuple):
>>>        return object[1]
>>>    else:
>>>        return magic_network_method(object)

注意 这里用isinstance进行类型/类检查是为了说明一点,类型检查一般来说并不是什么好方法,能不要用则不用。

前面的代码中使用isinstance函数查看对象是否为元组。如果是的话,就返回它的第2个元素,否则会调用一些“有魔力的”网络方法。
假设网络功能部分已经存在,那么问题已经解决了,目前为止是这样。但是程序还不是很灵活。如果某些聪明的程序员决定用十六进制数的字符串来表示价格,然后存储在字典中的键“price”下面呢?没问题,只要更新函数:

#不要这样做
>>>def getPrice(object):
>>>    if isinstance(object,tuple):
>>>        return object[1]
>>>    elif isinstance(object,dict):
>>>        return int(object['price']
>>>    else:
>>>        return magic_network_method(object)

现在是不是已经考虑到了所有可能性?但是如果某些人希望为存储在其他键下面的价格增加新的字典类型呢?那又怎么办呢?可以再次更新getPrice函数,但是这种工作还要做多长时间?每次有人要实现价格对象的不同功能时,都要再次实现你的模块。但是如果这个模块已经卖出去了并且转到了其他更酷的项目中,那么要怎么应付客户?显然这是个不灵活且不切实际的实现多种行为的代码编写方式。
那么应该怎么办?可以让对象自己进行操作。每个新的对象类型都可以检索和计算自己的价格并返回结果,只需向它询问价格即可。
2.多态和方法
程序接收到一个对象,完全不了解该对象的内部实现方式———它可能有多种“形状”。你要做的就是询问价格,这就够了,实现方法是我们熟悉的:

>>>object.getPrice()
>>>2.5

绑定到对象特性上面的函数称为方法(method)。我们已经见过字符串,列表和字典方法。实际上多态也已经出现过:

>>>'abc'.count('a')
>>>1
>>>[1,2,'a'].count('a')
>>>1

对于变量x来说,不需要知道它是字符串还是列表,就可以调用它的count方法,不用管它是什么类型(只要你提供一个字符作为参数即可)。
让我们做个实验吧,标准库random中包含choice函数,可以从序列中随机选出元素。给变量赋值:

>>>from random import choice
>>>x = choice(['Hello , World!',[1,2,'e','e',4]])

运行后,变量x可能会包含字符串’Hello,world!’,也有可能包含列表[1,2,’e’,’e’,4]———不用关心到底是哪个类型。要关心的就是在变量x中字符e出现多少次,而不管x是字符串还是列表。可以使用刚才的count函数,结果如下:

>>>x.count('e')
>>>2

本例中,看来是列表胜出了。但是关键点在于不需要检测类型:只需要知道x有个叫做count 的方法,带有一个字符作为参数,并且返回整数值就够了。如果其他人创建的对象类也有count方法,那也无所谓,你只要像用字符串和列表一样使用该对象就行了。
3.多态的多种形式
任何不知道对象到底是什么类型,但是又要对对象“做点什么”的时候,都会用到多态。
这不仅限于方法,很多内建运算符和函数都有多态的性质,考虑下面的这个例子:

>>>1+2
>>>3
>>>'Fish'+'license'
>>>'Fishlicense'

这里的加运算符对于数字(本例中为整数)和字符串(以及其他类型的序列 )都能起作用。为说明这一点,假设有个叫做add的函数,它可以将两个对象相加。那么可以直接将其定义成上面的形式(功能等同但比operator模块中的add函数效率低些)。

>>>def add(x,y):
>>>    return x+y
对于很多类型的参数都可以用:
>>>add('Fish','license')
>>>'Fishlicense'

看起来有些傻,但是关键在于参数可以是任何支持加法的对象。如果需要编写打印对象长度消息的函数,只需对象具有长度(len函数可用)即可。

>>>def length_message('Fnord')
>>>The length of 'Fnord' is 5
>>>length_message([1,2,3])
>>>The length of [1,2,3] is 3

很多函数和运算符都是多态的———你写的绝大多数程序可能都是,即便你并非有意这样。只要使用多态函数和运算符,就会与“多态”发生关联。事实上,唯一能够毁掉多态的就是使用函数显式地检查类型(或者类)。
注意 这里所讨论的多态的形式是Python式编程的核心,也是被称为“鸭子类型”。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值