面向对象之【继承】
1、继承的概念:
1.1、多个事物(类)之间的所属关系,子类默认继承父类的所有方法和属性。
1.2、所有类默认继承object类,object类称为顶级类或者基类,其他子类叫做派生类。
2、继承的方式:
2.1、单继承——子类只继承一个父类
(1)子类继承父类,在定义类时,小括号()中填入父类的名字。
class 子类类名(父类类名):
代码块
(2)子类会继承父类的所有属性和方法。
2.2、多继承:子类继承多个父类
子类同时继承多个父类时,如果父类中有同名方法和属性,默认使用第一个父类的同名方法和属性。
2.3、多层继承:
C继承自B,B继承自A
3、重写:子类重写父类的同名方法和属性:
(1)在子类方法中,定义同名属性和方法,此时默认调用子类的属性和方法。
(2)子类重写父类的同名方法和属性,仍然想调用父类的方法
方法一:在子类中定义一个实例方法,再次封装父类的同名属性和实例方法
1、调用父类的__init__初始化方法,初始化父类的属性:父类类名.__init__(self)
2、调用父类的同名实例方法:父类类名.实例方法名(self)
注意:当子类和多个父类都存在同名方法和属性时,调用属性前都应该先对自己的属性进行初始化,假设先调用了其中一个父类的同名方法和属性,后续调用其他父类或者子类的同名方法,此时不做重新做初始化的话,所获取的属性都是默认等于上一次调用时初始化的属性。
方法二:在子类中用super()方法调用父类,下面两种写法皆可,一般使用第二种写法
1、super(当前类名,self).方法名()
2、super().方法名()
使用super方法更为简洁,重要的是当父类名称变化,用方法一则要批量去修改父类类名,用方法二我们不用过多关注父类类名的变化。
4、私有权限
4.1、定义私有属性与私有方法:父类中的私有属性和方法【不继承】给子类
(1)格式:在属性和方法名前面加__(两个下划线)
(2)不能通过对象访问私有属性和方法
(3)子类无法继承父类的私有属性和私有方法
4.2、访问和修改私有属性与私有方法:
(1)私有方法只能在类里面通过定义其他方法来进行访问和修改
(2)一般用定义get_xx函数来获取私有属性,命名习惯只是约定俗成,并非一定要加上get; set_xx函数来修改私有属性,命名习惯只是约定俗成,并非一定要加上set
“”"
# -*- encoding: utf-8 -*-
'''
# 1、单继承
# 定义父类Mater
class Master(object):
def __init__(self):
# 定义属性
self.kongfu = '古法煎饼果子配方'
# 定义实例化方法
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
# 定义子类Prentice,继承父类Master
# class 子类类名(父类类名):
# 代码块
class Prentice(Master):
# 什么都不做
pass
# 用子类创建一个对象
dage = Prentice()
# 对象访问实例属性
print(dage.kongfu) # 古法煎饼果子配方
# 对象调用实例方法
dage.make_pancake() # 用古法煎饼果子配方制作煎饼果子
# Prentice类什么都没有做,默认继承了父类Master中的属性和实例方法。
'''
'''
# 2、多继承
# 定义父类1--Mater
class Master(object):
def __init__(self):
# 定义属性
self.kongfu = '古法煎饼果子配方'
# 定义实例化方法
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
# 定义父类2--school
class School(object):
def __init__(self):
# 定义属性
self.kongfu = '新式煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
# 定义子类Prentice,继承父类Master和School
# class 子类类名(父类类名1, 父类类名2):
# 代码块
class Prentice(Master, School):
# 什么都不做
pass
# 用子类创建一个对象
dage = Prentice()
print(dage.kongfu) # 古法煎饼果子配方
dage.make_pancake() # 用古法煎饼果子配方制作煎饼果子
# 默认使用第一个父类的同名方法和属性
# 如果希望打印出School里面的新式煎饼果子配方,交换一下定义子类时继承父类的顺序,School放在Master前面即可。
'''
'''
# 3、子类重写父类同名属性和方法
class Master(object):
def __init__(self):
self.kongfu = '古法煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '新式煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class Prentice(Master, School):
def __init__(self):
# 在子类中定义同名属性
self.kongfu = '无敌独创煎饼果子配方'
# 在子类中定义同名实例方法
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
dage = Prentice()
# 子类和父类具有相同属性和方法,默认调用子类的属性和方法
print(dage.kongfu) # 无敌独创煎饼果子配方
dage.make_pancake() # 用无敌独创煎饼果子配方制作煎饼果子
'''
'''
# 子类重写父类同名属性和方法后,仍然想调用父类的属性和方法
# 方法一
class Master(object):
def __init__(self):
self.kongfu = '古法煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '新式煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class Prentice(Master, School):
def __init__(self):
# 在子类中定义同名属性
self.kongfu = '无敌独创煎饼果子配方'
# 在子类中定义同名实例方法
def make_pancake(self):
# 如果是父类同名方法和属性先被调用,父类属性会覆盖子类中的属性
# 故调用子类的属性前,需要重新初始化子类的属性
self.__init__()
print(f'用{self.kongfu}制作煎饼果子')
# 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装
def master_make_pancake(self):
# 父类类名.方法名(self)
# self一定要加,指调用时的传入的对象
# 调用父类实例方法前,需调用父类的__init__初始化方法,保证调用到的属性是父类的属性
Master.__init__(self)
Master.make_pancake(self)
def School_make_pancake(self):
# 如果调用__init__初始化方法,调用到的属性是子类的属性或者是上一次调用的其他父类的属性
School.__init__(self)
School.make_pancake(self)
dage = Prentice()
# 调用父类Master同名方法前
print(dage.kongfu) # 无敌独创煎饼果子配方
# 调用Master父类中的同名方法和属性
dage.master_make_pancake() # 用古法煎饼果子配方制作煎饼果子
# 调用父类Master同名方法后
print(dage.kongfu) # 古法煎饼果子配方
# 调用School父类中的同名方法和属性
dage.School_make_pancake() # 用新式煎饼果子配方制作煎饼果子
# 调用父类School同名方法后
print(dage.kongfu) # 新式煎饼果子配方
dage.make_pancake() # 用无敌独创煎饼果子配方制作煎饼果子
'''
'''
# 4、多层继承
# Tusun继承自Prentice,Prentice继承自Master和School
class Master(object):
def __init__(self):
self.kongfu = '古法煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '新式煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class Prentice(Master, School):
def __init__(self):
self.kongfu = '无敌独创煎饼果子配方'
# 在子类中定义同名实例方法
def make_pancake(self):
self.__init__()
print(f'用{self.kongfu}制作煎饼果子')
# 一次性调用父类的同名属性和方法
def old_make_pancake(self):
Master.__init__(self)
Master.make_pancake(self)
School.__init__(self)
School.make_pancake(self)
class Tusun(Prentice):
pass
xiaodi = Tusun()
print(xiaodi.make_pancake()) # 用无敌独创煎饼果子配方制作煎饼果子
xiaodi.old_make_pancake()
# 用古法煎饼果子配方制作煎饼果子
# 用新式煎饼果子配方制作煎饼果子
# 多层继承中最底层的子类完美继承了父类以及父类的父类中的属性以及方法。
'''
'''
# 子类重写父类同名属性和方法后,仍然想调用父类的属性和方法
# 方法二
# 1、super(当前类名,self).方法名()
# 2、super().方法名()
class Master(object):
def __init__(self):
self.kongfu = '古法煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class School(Master):
def __init__(self):
self.kongfu = '新式煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
# 调用School的父类Master的make_pancake()
# super(School, self).__init__()
# super(School, self).make_pancake()
super().__init__()
super().make_pancake()
class Prentice(School):
def __init__(self):
self.kongfu = '无敌独创煎饼果子配方'
# 在子类中定义同名实例方法
def make_pancake(self):
self.__init__()
print(f'用{self.kongfu}制作煎饼果子')
# 一次性调用父类的同名属性和方法(父类School和父类的父类Master)
def old_make_pancake(self):
# super(Prentice, self).__init__()
# # 1、此时只调用到了父类School中的make_pancake()
# # 2、在调用到的父类School中的make_pancake() 同样用super去调用School的父类Master的make_pancake()
# super(Prentice, self).make_pancake
super().__init__()
super().make_pancake()
dage = Prentice()
# dage.make_pancake() # 用无敌独创煎饼果子配方制作煎饼果子
dage.old_make_pancake()
# 用新式煎饼果子配方制作煎饼果子
# 用古法煎饼果子配方制作煎饼果子
'''
# 5、私有权限
# 5.1、定义私有属性和私有方法
# 5.2、获取和修改私有属性
class Master(object):
def __init__(self):
self.kongfu = '古法煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '新式煎饼果子配方'
def make_pancake(self):
print(f'用{self.kongfu}制作煎饼果子')
class Prentice(Master, School):
def __init__(self):
self.kongfu = '无敌独创煎饼果子配方'
# 定义私有属性
self.__money = 5000000
# 一般定义 get_xx函数来获取私有属性
def get_money(self):
return f'私房钱{self.__money}'
# set_xx函数来修改私有属性
def set_money(self):
self.__money = 500
return f'私房钱变成了{self.__money}'
def __my_money(self):
print(f'私房钱{self.__money}')
# 在子类中定义同名实例方法
def make_pancake(self):
self.__init__()
print(f'用{self.kongfu}制作煎饼果子')
print(f'私房钱{self.__money}')
# 一次性调用父类的同名属性和方法
def old_make_pancake(self):
Master.__init__(self)
Master.make_pancake(self)
School.__init__(self)
School.make_pancake(self)
class Tusun(Prentice):
pass
dage = Prentice()
# 用对象访问私有属性__money,报错
# 对象不能直接访问私有属性和方法
# print(dage.__money) # AttributeError: 'Prentice' object has no attribute '__money'
# 通过类中的方法
# dage.__my_money() # AttributeError: 'Prentice' object has no attribute '__my_money'
print(dage.get_money()) # 私房钱5000000
print(dage.set_money()) # 私房钱变成了500
xiaodi = Tusun()
# 子类无法继承父类的私有属性和私有方法
# print(xiaodi.__money) # AttributeError: 'Tusun' object has no attribute '__money'
# xiaodi.__my_money() # AttributeError: 'Tusun' object has no attribute '__my_money'
print(xiaodi.get_money()) # 私房钱5000000
print(xiaodi.set_money()) # 私房钱变成了500