最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

Python3萌新入门笔记(28)

Python教程 小楼一夜听春语 1925浏览 0评论

这一篇教程是关于类的最后一部分内容。

八、多继承(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)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (1)

  1. 头像
    #定义饲养员 class Feeder: def feed_monkey(self, monkey): monke.monkey_eat() (monke 少了一个s)
    feith1年前 (2018-11-07)回复