python 3.2 对象的的特性 -- 继承 组合

1、继承总结 is -a 的问题

什么是继承 ? 继承是一种新建类的方式,新建的类

为何用继承? 子类会遗传父类的属性,所以继承解决类于类之间的代码冗余

继承是一种同一种维度下事务的遗传,有着相似的功能点

继承讲解了 is -a的关系 ,一个交通工具的范围里有汽车 ,飞机 ,轮船 ,那么每一个子类可以继承父类的功能和数据,解决的对象冗余
继承中新式类和经典类,涉及的多继承和单继承,以及继承延申的菱形问题,又包含了广度优先和深度优先,最后python统一一个标准mixin,可以小范围的额外的使用多继承。
mixin的规范 不论对继承中的父类和子类来说,都是某一维度内的东西。

1 继承的优点 - 解决类属性的冗余

如何继承
print(Sub.__bases__)  # 查看继承的父类的名称


一    解决 类中的属性冗余


class OldboyPeople():

        school = 'oldboy'


class Stuend(OldboyPeople):


        def __init__(self,name,age,smale):

                self.name  = name
                self.age =age
                self.smale = smale

        def choose(self):
                print('%s 正在选课'%(self.name))



class Terchar(OldboyPeople):

        def __init__(self,name,age,male,salar,level):
                self.name = name
                self.age = age
                self.male = male
                self.salar = salar
                self.level = level


        def score(self,stu,num):
                stu.num = num


stu= Stuend('zhangsan',18,'man')
ter = Terchar('laoshi',90,'man',9000,'10')


print(stu.school)

子类派生中重用父类方法的方式一 指名道姓

在子类派生的新方法中重用父类的功能方法一
类属性的 继承于 父类


 父类有的函数f1 ,子类如果也有的话,用子类的

 使用不依赖继承关系的 重用父类的方法


class OldboyPeople():

        school = 'oldboy'
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender

        def f1(self):
            print('111')


class Stuend():

        def __init__(self,name,age,gender):
            OldboyPeople.__init__(self,name,age,gender)
                # 在子类派生的新方法中 重用了父类的功能,在这个基础之上,扩展了自己的新的功能

        def choose(self):
            print('%s 正在选课'%(self.name))



class Terchar():

        def __init__(self,name,age,gender,salar,level):
            OldboyPeople.__init__(self,name,age,gender)
                # 在子类派生的新方法中 重用了父类的功能,在这个基础之上,扩展了自己的新的功能
                # 在调用 类函数的方法,没有自动传对象名,所以要加上空对象,调用类的函数
            self.salar = salar
            self.level = level


        def score(self):
            OldboyPeople.f1(self)
            print('2222222')


stu= Stuend('zhangsan',18,'man')
ter = Terchar('laoshi',90,'man',9000,'10')

ter.score()


# 指名道姓的调用某一个类的功能,不依赖 继承关系

2继承中属性查找的优先级


继承不要搞太多层,一般是3层
太多的属性,如何快速的的查找?

继承背景下的属性查找的路径 就是  对象自己,类,父类

 
class foo():

    def f1(self):
        print('foo,1111')

    def f2(self):
        print('foo 2222')
        self.f1()



class bar(foo):

    def f1(self):
        print('bar 1111')

stu = bar()


stu.f2()


检验继承背景下的属性查找优先级


需求 调用f2 ,要打印 foo 1111 ,实现

class foo():

    def __f1(self):
        print('foo,1111')

    def f2(self):
        print('foo 2222')
        self.__f1()



class bar(foo):

    def f1(self):
        print('bar 1111')

stu = bar()


stu.f2()


使用 类 隐藏函数的功能使函数名发生变形,让执行顺序发生改变。

3类继承的实现原理 - 新式类 C3算法

类的继承的实现原理


class Aaa():
    pass

print(Aaa.__bases__)

(<class 'object'>,)  在Python3 中如果一个类没有继承任何类的话,解释器会自动继承一个 object类。

那么在Python3 中,只要使继承了object 那么该子类的子子孙孙类都称之为新式类
那么在Python2 中,没有继承了object 那么该子类的子子孙孙类都称之为经典类


如果兼容Python2 的程序也要 继承 object



   继承的菱形问题,一个子类继承的多条件分支最总汇聚到一个非object类,在菱形继承下
            新式类 与经典类  关于属性查找方式不同



新式类:  广度有先
经典类:  深度有先

python3 新式类的广度查找


class A():
    def f1(self):
        print('A....')
    pass

class B(A):
    # def f1(self):
    #     print('B....')
    pass

class C(A):
    def f1(self):
        print('C....')
    pass

class D(B,C):
    pass

obj = D()
obj.f1()


在菱形继承的情况下,解决为什么要广度优先的排序,由C3算法实现


查看排序的列表的方法使

print(D.mro())

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]


继承反应的问题 就是  is -a 的意思

 为什么要让子类继承父类 ,说明 子类满足父类的某一种属性,而多继承违背了这种关系
 为什么python的设计者,设计了这种多继承的关系 ?

为了让子类最大限度的使用父类的代码,
为了让一个体 有多个不同的维度,更加的广泛,
如何防止多继承的滥用?
Python给出了标准使用 mixin

mixin 标准 白话就是在
在相同维度得情况下,(父类),为同维度下的个体(子类),增加了其他的功能。

例如 交通工具 这个父类  , 汽车, 飞机,轮船,这3个子类。
fly_mixin(可以飞的功能) 这个类,对于子类来说可以多继承使用。
那么这个功能必须使单一 ,也不依赖子类的实现。有没有继承,只是少了这个功能,不影响子类的实现


class B():
    # def f1(self):
    #     print('B....')
    pass

class C_mixin():
    def f1(self):
        print('C....')
    pass

class D(C_mixin,B): #在使用多继承的时候,表达归属关系的类放在最右边。其他的类都是功能类,混入的功能,
    pass

obj = D()
obj.f1()

4子类派生的新方法中重用父类功能的方式二 < super 属性的查找和 继承中的属性查找 相似 >

使用 super关键字, 调用 super(当前的类名,self对象名)语法格式,会返回一个特殊的对象,
super(Stuend,self). 属性会参照当前类的mro列表中,从父类开始,从左往右找。(严谨一点就是属性发起者的类的mro列表的父类开始找)
所以  在子类派生的新方法中重用父类功能的,不需要传对象名了

严格按照依赖继承的,会自动传参
class OldboyPeople():

        school = 'oldboy'
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender

        def f1(self):
            print('111')


class Student(OldboyPeople):

        def __init__(self,name,age,gender,class_num):
            super(Student,self).__init__(name,age,gender) # 重用父类的功能不需要再传入对象名

            # OldboyPeople.__init__(self,name,age,gender)
            self.class_mun =class_num

        def choose(self):
            print('%s 正在选课'%(self.name))



class Terchar(OldboyPeople):

        def __init__(self,name,age,gender,salar,level):

            # OldboyPeople.__init__(self,name,age,gender)
            # super(Terchar, self).__init__(name,age,gender) # 在Python3 super关键字不需要在加入 当前类名和self
            super().__init__(name,age,gender)
            self.salar = salar
            self.level = level


        def score(self):
            # OldboyPeople.f1(self)
            print('2222222')
            super().f1()


stu= Student('zhangsan',18,'man','五年级')


# print(stu.__dict__) # 打印了 当前类的功能和重用父类的功能
# {'name': 'zhangsan', 'age': 18, 'gender': 'man', 'class_mun': '五年级'}
ter = Terchar('lisi',18,'male',9000,10)

ter.score()


加强认识(严谨一点就是属性发起者的类的mro列表的父类开始找)

问题,会不会报错?

class A():

    def test(self):
        # print('....')
        super(A, self).test()
class B():

    def test(self):
        print('....')


class C(A,B):

    # def test(self):
    #     print('....')
    pass

obj = C()
obj.test()


# 不会报错!!

print(C.mro())
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
定义 从上面的例子中,打印c的mro列表中看出,c的父类时A,A的父类是B 所以不会报错
但是在代码中 A和B 之间使没有继承关系的,但是还是以mro列表为准


升级 mro列表的认识


class A():

    def test(self):
        # print('....')
        super(A, self).aaa()
class B():

    def aaa(self):
        print('B  ....')


class C(A,B):

    def aaa(self):
        print('C  ....')
    pass

obj = C()
obj.test()


# 不会报错!!

print(C.mro())

[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]


!!  属性查找的关系
 继承:  对象没有的,去当前类去找,当前类没有去父类找,按照mro列表,从左到右,如果父类调用了属性发起者的函数,以mro表优先,不会掉头去调用当前类的函数
       super 属性查找, 只是跳过了 对象本身,和父类本身,  如果属性发起者的父类 super调用了函数,还是要以当前类的父类中去找,类本身有的话,也不会去执行。

总结
super的调用会返回一个对象,这个对象会参照 属性发起者的mro列表,去找 .之后属性,不要从肉眼层面去看,要看c3算法给的结果

2、组合的总结 has -a的问题

那么不同类,不同维度的东西如何组合,
比如 交通工具 --- 》 汽车 ----》 要烧什么油 ,,油和交通工具就不是一个维度的。
比如  人类 ---->老师 -----  >  课程   ,那么课程和人类也不是一个维度的。

汽车要烧汽油,老师要教课,如何在代码中把两个不同的类,进行组合使用哪。


在学习库的导入和 函数嵌套,就是用到了名称空间的概念,一个函数的属性,关联了另外一个名称空间
那么现在不同类的调用也是使用的是名称空间的概念
涉及一个实例A,调用实例B,,首先设置A的名称空间的一个属性等于实例B,那么,a.属性.B的功能和数据 才能点出来。
 from  .a import ls
 ls.xxx
从导入的形式上和组合几乎一致。

需求 学生、老师、课程 ,要求 查看老师和学生的课程。

分析  老师和学生 ,可以有一个父类
     课程  单一的,使用组合 连接老师和学生的实例


class School():

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    school = 'old'


class Student(School):
    def __init__(self, name, age, gender):
        super(Student, self).__init__(name, age, gender)


class Tercher(School):
    def __init__(self, name, age, gender, salary, level):
        super(Tercher, self).__init__(name, age, gender)
        self.salary = salary
        self.level = level


class Course():
    def __init__(self, name, price, period):
        self.name = name
        self.price = price
        self.period = period

    def tell(self):
        print('%s:%s:%s' % (self.name, self.price, self.period))


stu1 = Student('zhangsan', 19, 'male')
ter1 = Tercher('lisi',90,'man',9000,10)




python = Course('python',3000,'3Month')
linux = Course('linux',2000,'1Month')



stu1.courses = python
ter1.courses = [python,linux] # 这个列表里的元素就不能使字符串了,应该是对象

# stu1.courses.tell()

for courses_obj in ter1.courses:
    courses_obj.tell() # 对象使用功能



posted @ 2022-02-06 19:32  mmszxc  阅读(53)  评论(0)    收藏  举报