一、继承
Python⾯向对象的继承指的是多个类之间的所属关系,即⼦类默认继承⽗类的所有属性和⽅法。
继承作用:继承可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
在Python中,所有类默认继承object类,object类是顶级类或基类;其他⼦类叫做派⽣类。
class Being: # 定义一个类Being
def __init__(self): #初始化实例属性
self.num = 1 #在类里面添加实例属性self.属性名=值
def info_print(self): # 定义一个实例方法
print(self.num) # 在类里面访问实例属性self.属性名
class People(Being): # 定义一个类People,继承Being类
pass
p1 = People() # 创建People类的一个对象p1
p1.info_print() # 对象调用父类实例方法
p1.num # 对象访问父类实例属性
输出:1
class Being(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class People(Being):
pass
p1 = People()
p1.info_print()
输出:1
二、单继承
单继承:一个子类继承一个父类
class Master:
def __init__(self):
self.kongfu = "古法配方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(Master):
pass
daqiu = prentice()
print(daqiu.kongfu)
daqiu.make_cake()
输出:
古法配方
古法配方制作煎饼果子
二、多继承
多继承:一个子类同时继承多个⽗类
当⼀个类有多个父类的时候,默认使用第⼀个父类的同名属性和方法。
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(Master, School):
pass
daqiu = prentice()
print(daqiu.kongfu) # 同名属性,访问第一个父类的同名属性
daqiu.make_cake() # 同名方法,访问第一个父类的同名方法
print(daqiu.age) # 不同名属性,第一个父类正常
print(daqiu.name) # 不同名属性,非第一个父类报错
输出:
三、子类重写父类同名方法和属性
⼦类和父类具有同名属性和方法,默认使用子类的同名属性和方法。
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(Master, School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
daqiu = prentice()
print(daqiu.kongfu) # 同名属性,重写父类
daqiu.make_cake() # 同名方法,重写父类
#如果子类和父类有同名属性和方法,子类创建对象调用属性和方法,调用的是子类里面的同名属性和方法
# print(daqiu.age) # 不同名属性,报错
print(daqiu.name) # 不同名属性,报错
输出:
四、___mro___
Python的MRO即Method Resolution Order(方法解析顺序),即在调用方法时,会对当前类以及所有的基类进行一个搜索,以确定该方法之所在,而这个搜索的顺序就是MRO。
类名.__mro__,返回一个元组。
可以清晰地看到类的层级关系。
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School(Master):
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
print(prentice.__mro__)
print(type(prentice.__mro__))
print(list(prentice.__mro__))
输出:
(<class '__main__.prentice'>, <class '__main__.School'>, <class '__main__.Master'>, <class 'object'>)
<class 'tuple'>
[<class '__main__.prentice'>, <class '__main__.School'>, <class '__main__.Master'>, <class 'object'>]
五、子类调用父类的同名属性和方法
子类里如果有与父类同名的属性方法,调用这个属性方法,调用的是子类里面的,调用不到父类里面的属性方法。
如何实现同名属性方法,既能调用子类里面的,也能调用父类里面的呢?
- 1.在子类里定义一个函数
- 2.再次初始化父类属性(参数self)
- 3.调用父类方法(参数self)
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(Master, School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
def make_master_cake(self): # 调用父类方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化,类名.__init__(self)
Master.__init__(self)
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
daqiu = prentice()
print(daqiu.kongfu)
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()
print(prentice.__mro__)
输出:
独创配方 # 返回的是子类属性
独创配方制作煎饼果子 # 调用的是子类方法
古法配方制作煎饼果子 # 调用到了父类Master的方法
学校技术制作煎饼果子 # 调用到了父类School的方法
(<class '__main__.prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(Master, School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
def make_master_cake(self): # 调用父类方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化,类名.__init__(self)
Master.__init__(self)
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
daqiu = prentice()
daqiu.make_master_cake()
daqiu.make_school_cake()
print(daqiu.kongfu)
daqiu.make_cake()
print(prentice.__mro__)
输出:
古法配方制作煎饼果子
学校技术制作煎饼果子
学校技术 # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性
学校技术制作煎饼果子 # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性
(<class '__main__.prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
代码修正,
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(Master, School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
self.__init__() # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用子类方法前,先调用子类自己的初始化
print("{}制作煎饼果子".format(self.kongfu))
def make_master_cake(self): # 调用父类同名属性方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化,类名.__init__(self)
Master.__init__(self) # 父类类名.__init__(self),父类初始化调用一次,注意不要漏写self
Master.make_cake(self) # 父类类名.函数(self), 父类方法调用一次,注意不要漏写self
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
daqiu = prentice()
daqiu.make_master_cake()
daqiu.make_school_cake()
print(daqiu.kongfu)
daqiu.make_cake()
输出:
古法配方制作煎饼果子
学校技术制作煎饼果子
学校技术 # 因为先调用父类,这里子类同名属性仍然被父类属性覆盖
独创配方制作煎饼果子
六、多层继承
多层继承:大于两层的继承
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(Master, School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
self.__init__() # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用子类方法前,先调用子类自己的初始化
print("{}制作煎饼果子".format(self.kongfu))
def make_master_cake(self): # 调用父类同名属性方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化,类名.__init__(self)
Master.__init__(self) # 父类初始化调用一次,注意不要漏写self
Master.make_cake(self) # 父类方法调用一次,注意不要漏写self
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
class TuShun(prentice):
pass
xiaoqiu = TuShun() # 说明子类可以继承父类所有属性和方法
xiaoqiu.make_cake() # 调用父类prentice方法
xiaoqiu.make_master_cake() # 调用父类prentice的父类方法
xiaoqiu.make_school_cake() # 调用父类prentice的父类方法
print(xiaoqiu.make_cake) # 前一步调用父类prentice的父类school类,school类初始化后,属性是school类的属性
输出:
独创配方制作煎饼果子
古法配方制作煎饼果子
学校技术制作煎饼果子
print(TuShun.__mro__)
输出:
(<class '__main__.TuShun'>, <class '__main__.prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
七、super()调用父类方法
方法一:在子类里定义一个函数,在里面初始化父类属性、调用父类方法
⽅法⼀特点:代码冗余;⽗类类名如果变化,这⾥代码需要频繁修改。如果有多个父类,代码量重复增加。
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School(Master):
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
self.__init__() # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用子类方法前,先调用子类自己的初始化
print("{}制作煎饼果子".format(self.kongfu))
# def make_master_cake(self): # 调用父类同名属性方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化,类名.__init__(self)
# Master.__init__(self) # 父类初始化调用一次,注意不要漏写self
# Master.make_cake(self) # 父类方法调用一次,注意不要漏写self
#
# def make_school_cake(self):
# School.__init__(self)
# School.make_cake(self)
# ⽅法⼀:代码冗余;⽗类类名如果变化,这⾥代码需要频繁修改
def make_old_cake(self):
Master.__init__(self)
Master.make_cake(self)
School.__init__(self)
School.make_cake(self)
daqiu = prentice()
daqiu.make_old_cake() # 从输出可以看到,两个父类的同名方法都调用到了
daqiu.make_cake()
print(prentice.__mro__)
输出:
古法配方制作煎饼果子
学校技术制作煎饼果子
独创配方制作煎饼果子
(<class '__main__.prentice'>, <class '__main__.School'>, <class '__main__.Master'>, <class 'object'>)
方法二:super()方法,带参数写法, super(当前类名, self).函数()
方法二特点:super里的类名是当前类名,自己可以控制,防止改了类名而未改super里的类名。缺点是仍然需要注意上下保持一致,而且如果有多个父类,需要在多个父类里加入super代码。
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School(Master):
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
# 方法二(一):super(当前类名,self).函数()
super(School, self).__init__()
super(School, self).make_cake()
class prentice(School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
self.__init__() # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用子类方法前,先调用子类自己的初始化
print("{}制作煎饼果子".format(self.kongfu))
# def make_master_cake(self): # 调用父类同名属性方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化,类名.__init__(self)
# Master.__init__(self) # 父类初始化调用一次,注意不要漏写self
# Master.make_cake(self) # 父类方法调用一次,注意不要漏写self
#
# def make_school_cake(self):
# School.__init__(self)
# School.make_cake(self)
# ⽅法⼀:代码冗余;⽗类类名如果变化,这⾥代码需要频繁修改
# def make_old_cake(self):
# Master.__init__(self)
# Master.make_cake(self)
# School.__init__(self)
# School.make_cake(self)
# 方法二(一):super(当前类名,self).函数()
def make_old_cake(self): # 需要同时在当前类prentice的父类School里也加super()
super(prentice, self).__init__()
super(prentice, self).make_cake()
daqiu = prentice()
daqiu.make_old_cake()
daqiu.make_cake()
print(prentice.__mro__)
输出:
学校技术制作煎饼果子
古法配方制作煎饼果子
独创配方制作煎饼果子
(<class '__main__.prentice'>, <class '__main__.School'>, <class '__main__.Master'>, <class 'object'>)
<推荐使用以下方法>
方法三:super()方法,无参数写法, super().函数()
方法三特点:super()无参数写法,自动查找直接父类
使⽤super() 可以⾃动查找⽗类。调⽤顺序遵循 mro 类属性的顺序。⽐较适合单继承使⽤。
.
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School(Master):
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
# 方法二(一):super(当前类名,self).函数()
# super(School, self).__init__()
# super(School, self).make_cake()
# 方法二(二):super(当前类名,self).函数()
super().__init__()
super().make_cake()
class prentice(School):
def __init__(self):
self.kongfu = "独创配方"
def make_cake(self):
self.__init__() # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用子类方法前,先调用子类自己的初始化
print("{}制作煎饼果子".format(self.kongfu))
# def make_master_cake(self): # 调用父类同名属性方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化,类名.__init__(self)
# Master.__init__(self) # 父类初始化调用一次,注意不要漏写self
# Master.make_cake(self) # 父类方法调用一次,注意不要漏写self
#
# def make_school_cake(self):
# School.__init__(self)
# School.make_cake(self)
# ⽅法⼀:代码冗余;⽗类类名如果变化,这⾥代码需要频繁修改
# def make_old_cake(self):
# Master.__init__(self)
# Master.make_cake(self)
# School.__init__(self)
# School.make_cake(self)
# 方法二(一):super(当前类名,self).函数()
# def make_old_cake(self): # 需要同时在当前类prentice的父类School里也加super()
# super(prentice, self).__init__()
# super(prentice, self).make_cake()
# 方法二(二):super(当前类名,self).函数()
def make_old_cake(self):
super().__init__()
super().make_cake()
daqiu = prentice()
daqiu.make_old_cake()
daqiu.make_cake()
print(prentice.__mro__)
输出:
学校技术制作煎饼果子
古法配方制作煎饼果子
独创配方制作煎饼果子
(<class '__main__.prentice'>, <class '__main__.School'>, <class '__main__.Master'>, <class 'object'>)
八、定义私有(实例)属性和方法
默认情况下,只要继承关系建立,子类默认继承父类所有的属性和方法,这些能够继承给子类的属性方法叫共有权限。
如果有些属性和方法不想继承给子类了,私有权限,可以添加私有属性方法来实现。
注意:私有属性和私有方法只能在类里面访问和修改。,对某些属性方法起到保护作用。
.
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(School, Master):
def __init__(self):
self.kongfu = "独创配方"
self.__money = "一个亿" # 定义私有属性
def __printinfo(self): # 定义私有⽅法
print(self.kongfu)
print(self.__money)
def make_cake(self):
self.__init__() # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用子类方法前,先调用子类自己的初始化
print("{}制作煎饼果子".format(self.kongfu))
class TuShun(prentice):
pass
xiaoqiu = TuShun()
print(xiaoqiu.kongfu) # 独创配方
print(xiaoqiu.money) # AttributeError: 'TuShun' object has no attribute 'money'
print(xiaoqiu.__money) # AttributeError: 'TuShun' object has no attribute '__money'
xiaoqiu.printinfo # AttributeError: 'TuShun' object has no attribute 'printinfo'
xiaoqiu.__printinfo # AttributeError: 'TuShun' object has no attribute '__printinfo'
# ⼦类⽆法继承⽗类的私有属性和私有⽅法
九、获取和修改私有属性值
在Python中,在类里面,定义函数 get_属性名 ⽤来获取私有属性,定义 set_属性名 ⽤来修改私有属性值。
class Master:
def __init__(self):
self.kongfu = "古法配方"
self.age = 100
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class School:
def __init__(self):
self.kongfu = "学校技术"
self.name = "新东方"
def make_cake(self):
print("{}制作煎饼果子".format(self.kongfu))
class prentice(School, Master):
def __init__(self):
self.kongfu = "独创配方"
self.__money = "私有:一个亿"
def get_money(self):
print(self.__money) # 或者这里用 return self.__money,调用时用print
def set_money(self):
self.__money = "私有更新:十个亿"
def __printinfo(self):
print(self.kongfu)
print(self.__money)
def make_cake(self):
self.__init__() # 如果先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用子类方法前,先调用子类自己的初始化
print("{}制作煎饼果子".format(self.kongfu))
class TuShun(prentice):
pass
xiaoqiu = TuShun()
xiaoqiu.get_money()
xiaoqiu.set_money()
xiaoqiu.get_money()
print(prentice.__mro__)
输出:
私有:一个亿
私有更新:十个亿
(<class '__main__.prentice'>, <class '__main__.School'>, <class '__main__.Master'>, <class 'object'>)
十、私有类属性
class Dog:
__age = 3
@classmethod
def get_age(cls):
return cls.__age
wangcai = Dog()
result = wangcai.get_age()
print(result) # 3
十一、继承知识小结
PS: source,itheima