这一篇教程是关于类的最后一部分内容。
八、多继承(Multiple Inheritance)
注意:不要和多重继承搞混,多重继承是指C继承B,B继承A这样的继承形式。
示例代码:(多重继承)
class A: pass class B(A): pass class C(B): pass
多继承是指类能够继承自多个超类。
所以,在上一篇教程我们在使用__bases__特性时,能够看到bases是一个复数。
多继承的使用很简单,只需要在来名称后面的括号中写入超类的名称并用逗号分隔即可。
示例代码:(多继承)
class A: pass class B: pass class C(A,B): pass
不过要注意,当多个超类都具有相同的特性时,只会继承第一个(最左侧)超类中的特性。
在现实生活中,有很多这种情况,例如小学生既是学生又是儿童。
就像下面这段代码。
示例代码:
class Children: # 创建儿童类 age = 10 def activitie(self): # 定义活动方法 print('我周末去儿童游乐园玩!') class Student: # 创建学生类 grade = 3 def activitie(self): # 定义活动方法 print('我每天放学在家写作业!') class Pupil(Children, Student): # 创建小学生类 def __init__(self): print('我今年%d岁,已经上%d年级啦!' % (self.age, self.grade)) p = Pupil() # 显示输出结果为:我今年10岁,已经上3年级啦! p.activitie() # 显示输出结果为:我周末去儿童游乐园玩!
九、检查对象的特性
如果想知道一个对象是否具有某个特性,可以使用hasattr(o,name)函数,当包含指定特性的名称时,返回值为True;否则,为False。
借用上面的学生类,我们进行特性的检查。
c = Children() print(hasattr(c, 'age')) # 检查特性age,显示输出结果为:True print(hasattr(c, 'grade')) # 检查特性grate,显示输出结果为:False print(hasattr(c, 'activitie')) # 检查方法activitie,显示输出结果为:True print(hasattr(c, 'study')) # 检查方法study,显示输出结果为:False
另外,我们还可以检查一个对象的特性是否能被调用。
我们可以使用getattr(o,name,default)获取对象的特性,然后通过callable(object)检查。
print(callable(getattr(c, 'activitie', None))) # 显示输出结果为:True print(callable(getattr(c, 'study', None))) # 显示输出结果为:False
上方代码中,我们为getattr()函数指定了默认值None,这样当找不到特性时,返回值为False。
如果不设置默认值None,则会抛出异常。
AttributeError: ‘Children’ object has no attribute ‘study’
特性错误: ‘Children’ 对象不包含 ‘study’特性。
十、多态(Polymorphic)
多态的字面意思是多种形式。
在Python中是指多个不同类的对象,都具有一些共同的特性,这些对象中的任何一个对象,都可以调用这些共同的特性。但是,因为是不同类的对象,所以,在调用同一个特性时,会表现出不同的行为。
这里提到的对象允许外部访问的共同特性,也就是在前面我们提到过接口。
当我们处理多态对象时,只需要关心它所提供的接口。
例如,count()方法就是多态特性。
示例代码:
obj = '小楼棒,小楼帅,小楼好厉害!' # 变量引用字符串对象 print(obj.count('小楼')) # 显示输出结果为:3 obj = ('小楼', '樱井', '小楼', '明步') # 变量引用元组对象 print(obj.count('小楼')) # 显示输出结果为:2
在上方代码中,“obj”就是多态对象,它可以是不同的对象。
我们不管“obj”是什么对象(字符串或元组或其它),只需要关心它的接口中有没有count()这个方法。
如果有count()这个方法,就能够对对象进行处理。
但是,虽然调用的方法都是同一个名称,因为处理的是不同的对象,实际上具体的处理行为是不一样的。
接下来,我引用一个其它编程语言中的示例,来帮助大家了解多态。
动物园的饲养员(Feeder ),能够喂养狮子(Lion),老虎(Tiger)和狗熊(Bear)。
饲养员要对这些动物进行喂食的操作。
假设我们不做多态处理。
示例代码:(非多态)
# 定义动物 class Lion: # 定义狮子类 def lion_eat(self): # 定义进食函数 print('狮子在吃东西!') class Tiger: # 定义老虎类 def tiger_eat(self): # 定义进食函数 print('老虎在吃东西!') class Bear: # 定义狗熊类 def bear_eat(self): # 定义进食函数 print('狗熊在吃东西!') # 定义饲养员 class Feeder: def feed_lion(self, lion): # 定义喂养狮子的函数 lion.lion_eat() def feed_tiger(self, tiger): # 定义喂养老虎的函数 tiger.tiger_eat() def feed_bear(self, bear): # 定义喂养猴子的函数 bear.bear_eat() # 喂养过程 feeder = Feeder() lion = Lion() feeder.feed_lion(lion) # 显示输出结果为:狮子在吃东西! tiger = Tiger() feeder.feed_tiger(tiger) # 显示输出结果为:老虎在吃东西! bear = Bear() feeder.feed_bear(bear) # 显示输出结果为:狗熊在吃东西!
上方的代码虽然运行正常,但是如果给饲养员增加工作量,让他再多喂一只猴子。
我们就需要继续增加一些代码。
示例代码:(增加的代码)
#定义动物 class Monkey: def monkey_eat(self): print('猴子在吃东西!') #定义饲养员 class Feeder: def feed_monkey(self, monkey): monke.monkey_eat() # 喂养过程 monkey = Monkey() feeder.feed_monkey(monkey)
很显然,每增加一个喂养一个动物,我们都要增加这么多代码。
那么,通过多态处理呢?
示例代码:(多态)
class Lion: # 定义狮子类 def eat(self): # 定义进食函数 print('狮子在吃东西!') class Tiger: # 定义老虎类 def eat(self): # 定义进食函数 print('老虎在吃东西!') class Bear: # 定义狗熊类 def eat(self): # 定义进食函数 print('狗熊在吃东西!') class Feeder: # 定义饲养员类 def feed_animal(self, animal): # 定义喂食方法 animal.eat() # 喂养过程 feeder = Feeder() animal = Lion() feeder.feed_animal(animal) # 显示输出结果为:我是狮子,在吃东西! animal = Tiger() feeder.feed_animal(animal) # 显示输出结果为:我是狮子,在吃东西! animal = Bear() feeder.feed_animal(animal) # 显示输出结果为:我是狗熊,在吃东西!
在上方代码中,每一个动物的进食方法都采用了相同的名称,喂食方法只保留了一个。
并且,喂养过程中调用的喂食方法都是相同的。(因为喂食方法就一个)
这样,多个类中都有一个相同的特性(eat函数),实例对象也就具有了这个相同的特性(eat方法),所以,不管调用的时候是哪一种实例对象(变量animal),都可以调用这个特性(eat方法),但是因为调用这个特性的实例对象(动物)不同,所以产生的行为(eat方法的处理过程)是不同的。
这就是多态。
那么,对比之前未做多态处理的代码,有什么好处呢?
当同样需要增加喂养猴子时,通过多态处理的代码,只需要增加新的动物种类,以及喂养过程中对动物的实例化和调用喂养方法。
示例代码:(增加部分)
#定义动物 class Monkey: def eat(self): print('猴子在吃东西!') # 喂养过程 animal = Monkey() feeder.feed_animal(animal)
从这个示例我们也能够看出,喂食方法无需再重复定义,多喂养一种动物只需要定义一个新的类。
这也就说明了,多态能够提高代码的复用性,让代码更加精简易读,并且降低了代码的耦合度(紧密配合与相互影响的程度),提升了代码的扩展性。
另外,值得注意的是,Python中多态的概念不同于其它编程语言,在大多编程语言中,如果需要进行多态处理,会要求具有相同特性的类(例如上方代码中的狮子类、老虎类等)必须继承自同一个超类(需要定义Animal类),这样在调用特性时是通过超类寻找相应的子类。
而Python中无需这么做,就像上方的代码,我们并没有定义一个动物的超类,让动物的子类去继承这个超类。
所以,严格来说Python中没有多态这个概念,因为Python自身就是多态的语言。
本节知识点:
1、多继承
2、检查对象的特性
3、多态
本节英文单词与中文释义:
1、multiple:多个/多重
2、base:基本
3、children:儿童
4、age:年龄
5、grade:年级
6、pupil:小学生
7、activitie:活动
8、polymorphic:多态
9、animal:动物
10、lion:狮
11、tiger:虎
12、bear:熊
13、monkey:猴
14、eat:吃
15、feed:喂养
16、feeder:饲养员
转载请注明:魔力Python » Python3萌新入门笔记(28)