【循序渐进学Python】面向对象知多少——继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制,那么今天我们来学习面向对象的第二大特征——继承.
继承
什么是继承?
- 在程序中继承是指描述的是多个类之间的一个所属关系
父类和子类
-
例如一个类A里面的所有的属性和方法可以复用,这个时候可以通过继承的方式,传递到类B里面
-
这这里A类称之为父类(基类)
-
B类称之为子类(派生类)
-
在Python中子类(派生类)会继承父类(基类),那么子类就及继承了父类中的属性和方法,简化了子类的设计问题,便于后期的维护和升级
继承的作用
-
继承能够极大程度的减少代码中的冗余程度
-
继承便于系统的后期维护工作
单继承
概念
-
一个类只继承了一个父类
-
如果子类继承了父类,子类就继承了父类的属性和方法
实例:
class A(object):
def __init__(self):
self.money = 1000000
self.blood = "张三"
def work(self):
print(f"我是一名工程师,我叫{self.blood},一个月工资{self.money}")
class B(A):
pass
b = B()
b.work()
重写
-
子类继承了父类,子类重写父类的同名方法和属性
-
子类实现了父类的同名方法,为了做自己特有的事情可以进行重写
-
重写是指在子类中重新去写父类中已经拥有的方法,并且在子类中保持这个方法的名字不变
-
只有方法体发生改变,那么调用子类对象的这个方法以后都是子类中所写的
案例
class puti(object):
def __init__(self):
self.xue = "72变"
def func(self):
print("变变变")
class tang(object):
def __init__(self):
self.xi = "阿弥陀佛"
class sun(puti, tang):
def __init__(self):
self.guo = "吃桃子"
tang.__init__(self)
puti.__init__(self)
def func(self):
print("36变")
puti.func(self)
a = sun()
a.func()
print("我叫孙悟空我会%s,我还有%s,我也会%s" % (a.xue, a.xi, a.guo))
子类对父类中的方法进行重写并且子类调用父类的同名方法
场景
1.子类继承了父类,父类不能满足子类的需求。子类重写父类的同名方法
2.但是子类还想在其类内部使用父类的同名方法
实例:
class Shi(object):
def work(self, x, y):
return x + y
class Tu(Shi):
def work(self, x, y):
return Shi.work(self, x, y) / 2
tu = Tu()
i = tu.work(4, 6)
print(i)
子类调用父类的同名属性和方法的方式
1.子类中:
父类名.父类的同名方法(self)
案例:
# 调用父类同名方法
class Tang(object):
def __init__(self):
self.yu = "阿弥陀佛"
def work(self):
print("般若波罗蜜多心经!")
class Puti(object):
def __init__(self):
self.zuo = "筋斗云"
def kongfu(self):
print("72般变化")
class Guanyin(object):
def __init__(self):
self.jin = "紧箍咒"
def buff(self):
print("三根救命毫毛")
def kongfu(self):
print("跑")
class SunMonken(Tang, Puti, Guanyin):
def __init__(self):
self.zhi = "弼马温"
Tang.__init__(self)
Puti.__init__(self)
Guanyin.__init__(self)
Tang.work(self)
Puti.kongfu(self)
Guanyin.kongfu(self)
Guanyin.buff(self)
def look(self):
print("火眼金睛")
# 如果想让SunMonken拥有所有的父类的属性和方法以及自己的这个属性和方法,
# 在__init__方法分别调用每个父类的__init__方法和每个父类的方法
sun = SunMonken()
print("俺老孙叫孙悟空:我会念经:%s,\n我有:%s,\n还有:%s,\n当过:%s" % (sun.yu, sun.jin, sun.zuo, sun.zhi))
2.使用super
- super函数是用来获取指定的子类在继承链中的后一个类给当前子类的self
super(子类名, self).父类同名方法
- 一般情况下获取当前子类的直接父类的同名方法可以省略括号中的参数
super().父类同名方法
案例:在多层继承中有体现
多继承
概念
- 一个类继承了多个父类
注意:
-
子类继承了多个父类,则子类就会继承父类的所有的不同名的方法
-
如果多个父类的方法名相同子类只会继承第一个父类的这个方法
-
通过一个类创建对象成功后,必须要执行一次init方法(可能是自己类中的,或者是父类中的)
-
如果子类中没有init这个方法,那么所有的父类中的init方法只有第一个父类的执行了
-
如果子类中也有init方法,那么所有的父类中的init方法都不会执行
如何查看一个类的继承链?
类名.__mro__
- 如果通过子类创建一个对象,如果调用方法,它遵循的是类的继承连
实例:
class Tang(object):
def __init__(self):
self.yu = "阿弥陀佛"
def work(self):
print("般若波罗蜜多心经!")
class Puti(object):
def __init__(self):
self.zuo = "筋斗云"
def kongfu(self):
print("72般变化")
class Guanyin(object):
def __init__(self):
self.jin = "紧箍咒"
def buff(self):
print("三根救命毫毛")
def kongfu(self):
print("跑")
class SunMonken(Tang, Puti, Guanyin):
def __init__(self):
self.zhi = "弼马温"
def look(self):
print("火眼金睛")
# 子类调用父类的同名方法
def kongfu(self):
# 因为在子类中调用了指定父类的方法
# 所以父类中重名方法,不会按照继承链的顺序进行调用
# 而是会调用指定父类的方法
Guanyin.kongfu(self)
sun = SunMonken()
# 程序中子类里面定义了__init__方法所以所有的父类中的__init__方法都不会执行
# print(sun.yu)
# print("孙悟空:我会念经:%s\n,我有了:%s\n,还有:%s\n" % (sun.yu, sun.jin, sun.zuo))
sun.work()
sun.buff()
sun.look()
sun.kongfu()
print(SunMonken.__mro__)
结论
1.如果多个父类的方法名不相同子类可以全部继承
2.如果多个父类的方法名相同子类只会继承第一个父类的
3.如何决定子类继承哪个父类的属性看子类到底继承了哪个父类的init方法
4.如果子类中也有父类的同名方法,那么子类就会选择自己的这个方法
5.如果子类中也有init方法,那么所有的父类的属性都不会被继承
6.通过一个类创建对象,必须要执行一次init方法找init方法的顺序要遵循类的继承链
多层继承
- 多层继承和多继承其实是一个原理,包括调用父类中的同名方法,包括super函数的使用都是一样的原理
案例:
class Puti(object):
def __init__(self):
self.model = "筋斗云"
def kongfu(self):
print("72般变化")
def look(self):
print("金睛火眼")
class SunMonken(Puti):
def __init__(self):
self.wuqi = "金箍棒"
def look(self):
print("火眼金睛")
def kongfu(self):
print("36般变化")
class ChenXiang(SunMonken):
def __init__(self):
# 通过父类的名称直接进行调用
SunMonken.__init__(self)
# 通过super函数进行调用
# super函数会自动查找参数中子类的“父类”按照继承链的顺序找其后一个
# super(子类名称,self).子类中的同名方法
super(ChenXiang, self).__init__()
# 一般情况下获取当前子类的直接父类的同名方法可以省略括号中的参数
super().__init__()
super(SunMonken, self).__init__()
super(SunMonken, self).kongfu()
super(SunMonken, self).look()
self.bao = "宝莲灯"
print(ChenXiang.__mro__)
cx = ChenXiang()
print(cx.model)
print(cx.wuqi)
print(cx.bao)
cx.kongfu()
cx.look()