python精讲之面向对象(3)继承,多态

概述

面向对象三大特性:封装,继承和多态,

从字⾯理解就是多种形态 ⼀个对象可以以不同形态去呈现
⾯向对象三⼤特性:

  • 封装 :确保对象中数据的安全
  • 继承 :保证了对象的扩展性
  • 多态 :保证了程序的灵活性
    前面博客讲了封装,而这一章博客来讲讲继承,与多态

继承

继承提⾼了类的复⽤性。让类与类之间产⽣了关系。有了这个关系,才有了 多态的特性

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
在这里插入图片描述

代码实战说明

# 垃圾类
class Waste():
    w_name = '垃圾'

    # ‘垃圾’类的一个方法:回收垃圾
    def recycle_w(self):
        print('回收垃圾...')


# ‘有害垃圾’类
class Swaste(Waste):  # 括号中填写父类的变量名
    pass
# ‘可回收垃圾’类
class Gwaste(Waste):
	pass 

继承有什么好处?最大的好处是子类获得了父类的全部功能。Swaste和Gwaste就继承了Waste的全部功能
如下运行试试:

a1 = Waste()
a2 = Swaste()
a3 = Gwaste()
a1.recycle()
a2.recycle()
a3.recycle()

结果为:

回收垃圾...
回收垃圾...
回收垃圾...

虽然Swaste和Gwaste两个类中没有实质代码块内容,但是他们继承了Waste类的功能,所以可以运行recycle()

# 垃圾类
class Waste():
    w_name = '垃圾'

    # ‘垃圾’类的一个方法:回收垃圾
    def recycle(self):
        print('回收垃圾...')


# ‘有害垃圾’类
class Swaste(Waste):  # 括号中填写父类的变量名
    def run1(self):
        print('处理有害垃圾')
# ‘可回收垃圾’类
class Gwaste(Waste):
	def run2(self):
		print('回收可回收垃圾')
        
a1 = Waste()
a2 = Swaste()
a3 = Gwaste()
a1.recycle()
a2.recycle()
a2.run1()
a3.recycle()
a3.run2()
回收垃圾...
回收垃圾...
处理有害垃圾
回收垃圾...
回收可回收垃圾

实例关系

istance()方法大家知道吧,来检查一个对象是否是一个对象的实例,那么子类既然继承了父类,那他们的的实例是否有关系呢?
附:object是所有类的父类
在创建类的时候省略父类的话默认即是object

# 垃圾类
class Waste():
    w_name = '垃圾'

    # ‘垃圾’类的一个方法:回收垃圾
    def recycle(self):
        print('回收垃圾...')


# ‘有害垃圾’类
class Swaste(Waste):  # 括号中填写父类的变量名
    pass
# ‘可回收垃圾’类
class Gwaste(Waste):
	pass 
# 创建‘有害垃圾’类的实例hw
sw = Swaste()
gw = Gwaste
print('子类的实例sw与父类的是否存在关联:')
print(isinstance(sw, Waste))
print('子类的实例gw与父类的是否存在关联:')
print(isinstance(gw, Waste))
print('子类的实例sw与‘object’类的是否存在关联:')
print(isinstance(sw, object))
print('子类的实例gw与‘object’类的是否存在关联:')
print(isinstance(gw, object))
print('结论:子类默认继承‘object’类,与其存在关联!')
子类的实例sw与父类的是否存在关联:
True
子类的实例gw与父类的是否存在关联:
False
子类的实例sw与‘object’类的是否存在关联:
True
子类的实例gw与‘object’类的是否存在关联:
True
结论:子类默认继承‘object’类,与其存在关联

issubclass()

issubclass()方法可以检查一个类是否另一个类的子类

# 垃圾类
class Waste():
    w_name = '垃圾'

    # ‘垃圾’类的一个方法:回收垃圾
    def recycle(self):
        print('回收垃圾...')


# ‘有害垃圾’类
class Swaste(Waste):  # 括号中填写父类的变量名
    def run1(self):
        print('处理有害垃圾')
# ‘可回收垃圾’类
class Gwaste(Waste):
	def run2(self):
		print('回收可回收垃圾')


print(issubclass(Swaste,Waste))
print(issubclass(Swaste,Waste))
print(issubclass(Waste,object))
True
True
True

方法的重写

如果在⼦类中有和⽗类同名的⽅法,则通过⼦类实例去调⽤⽅法时,会调⽤ ⼦类的⽅法⽽不是⽗类的⽅法,这个特点我们称之为⽅法的重写(覆盖)
上面的实例子类中的方法名都与父类中的方法名不同,但是如果取方法名一样呢,会如何执行呢?

# 垃圾类
class Waste():
    w_name = '垃圾'

    # ‘垃圾’类的一个方法:回收垃圾
    def recycle(self):
        print('回收垃圾...')


# ‘有害垃圾’类
class Swaste(Waste):  # 括号中填写父类的变量名
    def recycle(self):
        print('处理有害垃圾')
# ‘可回收垃圾’类
class Gwaste(Waste):
	def recycle(self):
		print('回收可回收垃圾')

a1 = Waste()
a2 = Swaste()
a3 = Gwaste()
a1.recycle()
a2.recycle()
a3.recycle()
回收垃圾...
处理有害垃圾
回收可回收垃圾

我们发现上面实例中子类中的方法名与父类重合时,调用时用的是子类的方法,原理是什么呢?

  • 当我们调⽤⼀个对象的⽅法时:
    • 会优先去当前对象中寻找是否具有该⽅法,如果有则直接调⽤
      • 如果没有,则去当前对象的⽗类中寻找,如果⽗类中有则直接调⽤⽗类中的⽅法
        • 如果没有,则去⽗类中的⽗类寻找,以此类推,直到找到object,如果依然没有找到就报错了
  • 这样,我们就获得了继承的另一个好处:多态。

多重继承

类的多重继承

  • 在Python当中,定义一个类的时候可以同时继承多个父类,这种方式被称为多重继承

  • 也就是我们可以为⼀个类同时制定多个⽗类 可以在类名的()后边添加多个类,来实现多重继承

  • 多重继承,会使⼦类同时拥有多个⽗类,并且会获取到所有⽗类中的⽅法

  • 在开发中没有特殊情况,应该尽量避免使⽤多重继承。因为多重继承会让我 们的代码更加复杂

  • 如果多个⽗类中有同名的⽅法,则会先在第⼀个⽗类中寻找,然后找第⼆ 个,找第三个…前⾯会覆盖后⾯的

class A(object):
    def run1(self):
        print('A')
class B(object):
    def run2(self):
        print('B')
class C(A,B):
    pass
c = C()
c.run1()
c.run2()
A
B

super()

super()可以获取当前类的⽗类
并且通过super()返回对象调⽤⽗类⽅法时,不需要传递self
在子类继承父类时,也会继承父类的特殊方法,比如初始化方法__init__,但是因为方法重写问题会在使用时出现一些不便,那么可以使用super方法来解决一些问题

# 垃圾类
class Waste():
    def __init__(self,name):
        self.name = name
    # ‘垃圾’类的一个方法:回收垃圾
    def recycle(self):
        print('回收垃圾...')


# ‘有害垃圾’类
class Swaste(Waste):  # 括号中填写父类的变量名
    def __init__(self,name,kind):        
        super().__init__(name)
        self.kind = kind
    def recycle(self):
        print('处理',self.kind,self.name)
# ‘可回收垃圾’类
class Gwaste(Waste):
	def recycle(self):
		print('回收可回收',self.name)

a1 = Waste('垃圾')
a2 = Swaste('垃圾','有害')
a3 = Gwaste('垃圾')
a1.recycle()
a2.recycle()
a3.recycle()
回收垃圾...
处理 有害 垃圾
回收可回收 垃圾

如上实例,子类中多了新的__init__方法,但是使用super方法直接使用父类中的__init__方法,所以子类中的__init__方法使用的是父类中的方法

多态

Python中多态的特点
1、只关心对象的实例方法是否同名,不关心对象所属的类型;
2、对象所属的类之间,继承关系可有可无;
3、多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强;
4、多态是调用方法的技巧,不会影响到类的内部设计。

  • 多态是⾯向对象的三⼤特性之⼀。
    从字⾯理解就是多种形态 ⼀个对象可以以不同形态去呈现

我们再编写一个函数帮助我们来理解多态,这个函数接受一个Animal类型的变量:

def run(animal):
    animal.run()
    animal.run()
run_(Animal())

当我们传入Animal的实例时,run就打印出:


Animal is running...
Animal is running...
run(Dog())

当我们传入Dog的实例时,run_twice()就打印出:


Dog is running...
Dog is running...
run(Cat())

当我们传入Cat的实例时,run_twice()就打印出:

Cat is running...
Cat is running...

看上去没啥意思,但是仔细想想,现在,如果我们再定义一个Pig类型,也从Animal派生:

class Pig(Animal):
    def run(self):
        print('Pig is running slowly...')

当我们调用run_twice()时,传入Tortoise的实例:

run(Pig())
Pig is running slowly...
Pig is running slowly...

你会发现,新增一个Animal的子类,不必对run()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

多态的好处就是,当我们需要传入Dog、Cat、Pig……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Pig……都是Animal类型,
然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:

猜你喜欢

转载自blog.csdn.net/xdc1812547560/article/details/107723321