单继承下属性查找
子集查找,
	若自身没有值,会去父集中找,出现重复值,会优先选择子集中值
    
class Foo:
    def f1(self):
        print("Foo.f1")
    def f2(self):
        print("Foo.f2")
        self.f1() # self => obj
class Bar(Foo):
    def f1(self):
        print("Bar.f1")
obj = Bar()
obj.f2()
出现隐藏值,会通过父集中值来间接调用父集的隐藏值
class Foo:
    def __f1(self):   # _Foo__f1()
        print("Foo.f1")
    def f2(self):
        print("Foo.f2")
        self.__f1() # self._Foo__f1()
class Bar(Foo):
    def __f1(self):  # _Bar__f1()
        print("Bar.f1")
obj = Bar()
obj.f2()
多继承下属性查找
菱形继承:
非菱形继承:经典类和新式类,属性查找没有顺序要求了,都一样
1.新式类:广度优先查找
2.经典类:深度优先查找
class G:
    def test(self):
        print('from G')
class E(G):
    # def test(self):
    #     print('from E')
    pass
class D(G):
    # def test(self):
    #     print('from D')
    pass
class B(E):
    # def test(self):
    #     print('from B')
    pass
class F(G):
    # def test(self):
    #     print('from F')
    pass
class C(F):
    # def test(self):
    #     print('from C')
    pass
class A(B, C, D):
    # def test(self):
    #     print('from A')
    pass
f1 = A()
# f1.test()
print(A.__mro__)  # 只有新式才有这个属性可以查看线性列表,经典类没有这个属性
python3中统一都是新式类
pyhon2中才分新式类与经典类
采用C3线性算法
class People():
    school = 'sh'
    def __init__(self, name, age, course=None):
        self.name = name
        self.age = age
class Student(People):
    def __init__(self, name, age, course):
        # People.__init__(self, name, age)
        # super(Student, self).__init__(name, age)  # python2
        super().__init__(name, age)  # python3
并且本身 self 无需传值
class A:
    def test(self):
        print('A---->test')
        super().aaa()
class B:
    def test(self):
        print('B---->test')
    def aaa(self):
        print('B---->aaa')
class C(A,B):
    def aaa(self):
        print('C----->aaa')
# c = C()
# c.test()
# # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
# print(C.mro())
多态性
继承:解决冗余问题
多态类中继承:不是让子类遗传父类的属性和方法,  是用来给子类定制标准的
多态带来的特性:在不用考虑对象数据类型的情况下,直接调用对象的方法
# import abc  # abstract => 抽象
#
# # 该类已经为抽象类了
# class Animal(metaclass=abc.ABCMeta):
#
#     @abc.abstractmethod
#     def speak(self):
#         pass
#
#     # @abc.abstractmethod
#     def run(self):
#         pass
# class People(Animal):
#     def speak(self):
#         pass
#     # def jiao(self):
#     #     pass
#     pass
#
#
# class Dog(Animal):
#     def speak(self):
#         pass
#
#
# class Pig(Animal):
#     def speak(self):
#         pass
#     pass
#
# obj1 = People()
# obj2 = Dog()
# obj3 = Pig()
#
# obj1.speak()
# obj2.speak()
# obj3.speak()
可以看做同一种形态
class People():
    def speak(self):
        pass
    # def jiao(self):
    #     pass
    pass
class Dog():
    def speak(self):
        pass
class Pig():
    def speak(self):
        pass
    pass
组合
组合:一个对象拥有一个属性,该属性是另外一个对象
解决类与类之间的冗余问题:
    1. 继承: 满足什么是什么的关系
    2. 组合: 满足什么有什么的关系
    
class People():
    school = 'sh'
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
class Course():
    def __init__(self, course_name, course_period, course_price):
        self.course_name = course_name
        self.course_period = course_period
        self.course_price = course_price
class Student(People, Course):
    def __init__(self, name, age, gender,  course=None):
        if course is None:
            course = []
        self.courses = course
        super().__init__(name, age, gender)
    def choose_course(self, course):
        self.courses.append(course)
        print("%s 选课 成功 %s" % (self.name, self.courses))
class Teacher(People):
    def __init__(self, name, age, gender,  lever):
        self.lever = lever
        super().__init__(name, age, gender)
    def score(self, stu_obj, num):
        stu_obj.num = num
        print("%s老师给%s学生打了%s分" % (self.name, stu_obj.name, num))
python = Course('python','6month', 10000)
linux = Course('linux','5month', 20000)
stu1 = Student('EGON', 19, 'MALE')
stu1.courses.append(python)
stu1.courses.append(linux)
tea1 = Teacher('ly', 19, 'make', 10)
tea1.course = python