继承

# 1.继承的概念
'''
1.1 什么是继承?
    I:继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类,子类会遗传父类的属性
    II:需要注意的是:python支持多继承,在Python中,新建的类可以继承一个或多个父类

1.2 经典类和新式类
在python2中有经典类与新式类之分
    新式类:继承了object类的子类,以及该子类的子类子子类。。。
    经典:没有继承object类的子类,以及该子类的子类子子类。。。
        print(Parent1.__bases__)
        print(Parent2.__bases__)
在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类

经典类
class 类名:
    代码

新式类
class 类名(object):
    代码
'''


# 2.单继承
# 2.1定义父类
class Parent(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)
        return self.num


# 2.2定义子类
class Sub(Parent):
    pass


# 2.3创建对象
result = Sub()
# 2.4对象访问实例属性
print(result.num)
# 2.5对象调用实例方法
result.info_print()


# 3.多继承  一个类同时继承多个父类
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice(School, Master):
    pass


daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()


# ps:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法。

# 4.子类重写父类的同名属性和方法
# 独创配方
class Prentice1(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


print('子类重写父类的同名属性和方法')
daqiu1 = Prentice1()
print(daqiu1.kongfu)
daqiu1.make_cake()

print(Prentice.__mro__)


# PS:子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。

# 5.子类调用父类的同名属性和方法
class Prentice2(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        # 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 调用父类方法,但是为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
    def make_master_cake(self):
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)


print('子类调用父类的同名属性和方法')
daqiu2 = Prentice2()
daqiu2.make_cake()
daqiu2.make_master_cake()
daqiu2.make_school_cake()


# 6.多层继承
class Tusun(Prentice2):
    pass


print('多层继承')
tus1 = Tusun()
tus1.make_cake()
tus1.make_school_cake()
tus1.make_master_cake()


# 7.super()
class Parent(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


# 2.2定义子类
class Master3(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice3(Master3):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装
    def make_master_cake(self):
        Master3.__init__(self)
        Master3.make_cake(self)

    # 一次性调用父类的同名属性和方法
    def make_old_cake(self):
        # super().函数()
        super().__init__()
        super().make_cake()


print('super()')
daqiu = Prentice3()
daqiu.make_old_cake()

# ps:使用super() 可以自动查找父类。调用顺序遵循 `__mro__` 类属性的顺序。比较适合单继承使用。

# 9.属性查找
# 有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找……
class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.f1()  # obj.f1()

class Bar(Foo):
    def f1(self):
        print('Bar.f1')

b = Bar()
b.f2()

# b.f2()会在父类Foo中找到f2,先打印Foo.f2,然后执行到self.f1(),即b.f1(),仍会按照:对象本身->类Bar->父类Foo的顺序依次找下去,在类Bar中找到f1,因而打印结果为Foo.f1

# 10.私有权限--父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的
# 定义私有属性和方法:在属性名和方法名 前面 加上两个下划线 __。
# 获取和修改私有属性值:一般定义函数名`get_xx`用来获取私有属性,定义`set_xx`用来修改私有属性值。
class Foo:
    # 定义私有属性
    def __init__(self):
        self.__money = 2000000
    # 定义私有方法
    def __f1(self):  # 变形为_Foo__fa
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.__f1()  # 变形为self._Foo.__fa,因而只会调用自己所在的类中的方法

    # 获取私有属性
    def get_money(self):
        return self.__money

    # 修改私有属性
    def set_money(self):
        self.__money = 500

class Bar(Foo):
    def __f1(self):  # 变形为_Bar__f1
        print('Bar.f1')


b = Bar()
b.f2()  # 在父类中找到f2方法,进而调用b._Foo__f1()方法,同样是在父类中找到该方法
# 调用get_money函数获取私有属性money的值
print(b.get_money())
# 调用set_money函数修改私有属性money的值
b.set_money()
print(b.get_money())

# 11.mixins机制
# mixins机制核心:就是在多继承背景下尽可能地提升多继承的可读性
# ps:让多继承满足人的思维习惯=》什么"是"什么
class Vehicle:
    pass

class FlyableMixin:
    def fly(self):
        pass

class CivilAircraft(FlyableMixin, Vehicle):  # 民航飞机
    pass

class Helicopter(FlyableMixin, Vehicle):  # 直升飞机
    pass

class Car(Vehicle):  # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
    pass

# 12.总结
'''
1.什么是继承?
    I:继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类,子类会遗传父类的属性
    II:需要注意的是:python支持多继承,在Python中,新建的类可以继承一个或多个父类

2.经典类和新式类
    在python2中有经典类与新式类之分
        新式类:继承了object类的子类,以及该子类的子类子子类。。。
        经典:没有继承object类的子类,以及该子类的子类子子类。。。
            print(Parent1.__bases__)
            print(Parent2.__bases__)
    在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类
    
    在Python中子类可以同时继承多个父类,在子类继承了多个父类时,经典类与新式类的属性查找顺序不一样:
       经典类:深度优先,会在检索第一条分支的时候就直接一条道走到黑,即会检索大脑袋(共同的父类)
       新式类:广度优先,会在检索最后一条分支的时候检索大脑袋
3.多继承(一个类同时继承多个父类)
    1.多继承的优缺点
        优点:子类可以同时遗传多个父类的属性,最大限度地重用代码
        缺点:
            1、违背人的思维习惯:继承表达的是一种什么"是"什么的关系
            2、代码可读性会变差
            3、不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差,
            如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins
    2.为何要用继承:用来解决类与类之间代码冗余问题
    
4.继承的特点
    子类默认拥有父类的所有属性和方法
    子类重写父类同名方法和属性
    子类调用父类同名方法和属性
    
5.super()方法快速调用父类方法

6.通过类的内置属性__bases__可以查看类继承的所有父类

7.继承实现原理
    对于定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表
    print(Bar.mro())  新式类内置mro方法可以查看线性列表的内容,经典类没有该内置该方法
    Python会基于MRO列表按照从左到右的顺序依次查找基类,直到找到第一个匹配这个属性的类为止。
8.属性查找
    对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找……
    
9.私有权限--父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的
    定义私有属性和方法:在属性名和方法名 前面 加上两个下划线 __。
    获取和修改私有属性值:一般定义函数名`get_xx`用来获取私有属性,定义`set_xx`用来修改私有属性值。
    
10.mixins机制
    mixins机制核心:就是在多继承背景下尽可能地提升多继承的可读性
'''

posted @ 2021-01-26 10:43  啦啦哦  阅读(68)  评论(0编辑  收藏  举报