zoukankan      html  css  js  c++  java
  • day25 在继承的背景下属性查找的顺序、组合、多态与接口、鸭子类型

    回顾

    属性的存放位置:
            类中应该存储所有对象公共的内容
            对象中存储都是每个对象独有的(都不同)
    初始化函数:__init__
            给对象的属性赋初值 , 可以保证只要对象被创建就一定有相应的属性
           节省重复代码( 指初始化函数init给每个对象都会初始一份相应的属性)

    绑定方法指的是 :将类或对象与函数进行了绑定
            之所以绑定是为了提高整合度,后续在拿到对象就可以直接调用对象相关的所有属性,而无需关心数据是什么 如何处理
            类、对象其实都可以看作是一个存储数据的容器(有属性有方法)

    对象绑定方法:

             默认就是绑定给对象的
             当使用对象调用时 会自动传入对象本身作为第一个参数,执行该方法时,直接问self对应的这个对象要数据就可以了
             用类来调用时就是一个普通函数 该怎么传就这么传
    类绑定方法
             当执行该方法时,需要访问类中的内容而不需要对象中的内容时用类绑定方法
              @classmethod
             无论使用类还是对象来调用都会自动传入类本身作为第一个参数
    非绑定方法
              既不需要访问类中的内容 也不需要访问对象中的内容 那就作为非绑定方法 就是一个普通函数 没有自动传值的效果
             @staticmethod

    继承:说的是类与类之间的关系:【什么是什么的关系 如:猫是动物,猫继承了动物类】

               一个类继承另外一外类,继承的类称之为子类、派生类,被继承的类称之为父类、基类或超类

               一个类可以继承多个类。
                继承后,子类可以复用父类的内容 ,减少了类与类之间的代码冗余

    在继承背景下属性的查找顺序
             对象本身 -> 所在的类 -> 类的父类 -> .... object

    抽象类  指的是 把一系列类中的相同的特征和行为抽取 形成一个新的类 (公共父类)
              使用继承时 应该先抽象 再继承

    派生:  某子类拥有与父类不同的内容,优先使用自己的

    覆盖:子类出现了与父类完全相同的名字

    一切皆对象:在py3里面所有数据全是对象 包括 int list 模块 函数 .....包等等....

    在子类派生的新方法中重用父类的功能的两种方式:
           1.指名道姓地引用某一个类中的函数,与继承无关

           2. super() 得到一个对象,该对象专门用来访问父类中的属性,而父类参照mro列表顺寻查找父类
           py3:super()              
           py2:  super(自己的类名,自己的对象self)

    今日内容  

    一、属性查找顺序:

    --  在单继承背景下的属性查找的优先级:先在自己类中查找,没有就去父类中查找

    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()
    #Foo.f2
    #Bar.f1

    -- 在多背景下属性的查找顺序:

      1)如果一个子类继承多个分支,多个分支没有共同继承一个非object的类】,此时属性的查批优先级是

          对象-->对象的类--> 对象的父类-->该分支结束后再返回第二个父类,一个分支一个分支的找下去,最后找到object类,没有就报错,如下图先走B分支,走到G没有就找C 分支,最后找到Object类。新

         此种没有新式类与经典类之分,py3中默认G中继承了object类,py2中没写就真的就是没有,最后也不会找到object类。

    2)菱形继承背景下,属性查找的优先级:菱形指的是一个类有多个分支继承,最后会继承到一个公共的类。

                  python中的两种类【新式类、经典类】

                  新式类:直接或间接继承了object的类. ---    python3中都是新式类,因为默认继承ogject

                                从左往右,从第一个分支找,找到object的子类,再回到第二个分支,同样找到object的子类,依此类推,在最后一个分支找到顶级类,object类

                                查找其他路线(基于C3算法),A.mro()   => 得到一个属性查找顺序的列表

                 经典类:没有【直接或间接】继承object的类,都称之为经典类, python2不会默认继承object类,所有只有py2中才有经典类,而且没有继承object类

                               从左往右,从第一个分支找,一条线找到底,没有就从第二个分支找。

    二、组合:

    1. 什么组合? 组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象

    2. 为何要用组合?通过为某一个对象添加属性【属性的值是另外一个类的对象】的方式,可以间接地将两个类关联/整合/组合到一起,从而减少类与类之间代码冗余

    class Foo1:
    pass

    class Foo2:
    pass

    class Foo3:
    pass

    class Bar():
    x = 123

    obj_from_bar = Bar()
    obj1 = Foo1()
    obj2 = Foo2()
    obj3 = Foo3()

    obj1.attr1 = obj_from_bar
    obj2.attr1 = obj_from_bar
    obj3.attr1 = obj_from_bar

    obj1.attr1.x
    obj2.attr1.x
    obj3.attr1.x

    3. 什么时候用组合?

        让学生/老师有选课的功能,新增一个课程类,如下:

    class OldboyPeople:
    school = 'oldboy'
    def __init__(self, name, age, sex):
    self.name = name
    self.age = age
    self.sex = sex


    class OldboyStudent(OldboyPeople):
    school = 'oldboy'

    def __init__(self, name, age, sex, score=0):
    # OldboyPeople.__init__(self,name, age,sex)
    super(OldboyStudent,self).__init__(name, age, sex)
    self.score = score

    def choose_coure(self):
    print('%s choosing coures' % self.name)


    class OldboyTeacher(OldboyPeople):
    school = 'Oldboy'

    def __init__(self, name, age, sex, level):
    super().__init__(name,age, sex)
    # OldboyPeople.__init__(self,name,age, sex)
    self.level = level

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


    class Course:
    def __init__(self,c_name, c_price, c_period):
    self.c_name = c_name
    self.c_price = c_price
    self.c_period = c_period


    python = Course('python', 1900, '5month')

    stu1 =OldboyStudent('fanny',17, 'female')
    stu1.course = python
    print(stu1.course.c_name)
    print(stu1.course.c_price)
    print(stu1.course.c_period)

    tea1 = OldboyTeacher('egon', 18, 'male',100)
    tea1.course = python
    print(tea1.course.c_name)
    print(tea1.course.c_price)
    print(tea1.course.c_period)

     问题:是否可以减少代码冗余问题?将冗余部分放到课程类中

    class OldboyPeople:
    school = 'oldboy'
    def __init__(self, name, age, sex):
    self.name = name
    self.age = age
    self.sex = sex


    class OldboyStudent(OldboyPeople):
    school = 'oldboy'

    def __init__(self, name, age, sex, score=0):
    # OldboyPeople.__init__(self,name, age,sex)
    super(OldboyStudent,self).__init__(name, age, sex)
    self.score = score

    def choose_coure(self):
    print('%s choosing coures' % self.name)


    class OldboyTeacher(OldboyPeople):
    school = 'Oldboy'

    def __init__(self, name, age, sex, level):
    super().__init__(name,age, sex)
    # OldboyPeople.__init__(self,name,age, sex)
    self.level = level

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


    class Course:
    def __init__(self,c_name, c_price, c_period):
    self.c_name = c_name
    self.c_price = c_price
    self.c_period = c_period

    def tel_info(self):
    print('<课程名称:%s 价钱:%s 周期:%s>'% (self.c_name,self.c_price, self.c_period))


    python = Course('python', 1900, '5month')

    stu1 =OldboyStudent('fanny',17, 'female')
    stu1.course = python
    stu1.course.tel_info()

    tea1 = OldboyTeacher('egon', 18, 'male',100)
    tea1.course = python
    tea1.course.tel_info()

    三、多态与接口、鸭子类型

    --  什么是多态:指的是同一种/类事物的不同形态,但不同形态需遵循一个共同的规范【需跟父类有相同名字的方法】

    --   为何要用多态:

         提供了一个接口,父类就是一个规范,外界只要知道父类的有什么功能就可以了,

         参照父类中的【定义的函数名跟在父类中有就行了】方法使用,而不需要关心对象内部以及对象所在的类有什么。如len()方法,随便给一个对象就可以统计长度

    --   如何用多态: 要想使用接口的便利,必须如下这样:

         1)父类Animal只是用来建立规范的,不能用来实例化的,更无需实现内部的方法

         2) 子类中必须依照定义跟父类相同名字的方法【具体功能自定】

         3) 为了强制让子类完全依照父类,可以给父类加装饰器 。一旦没有按照父类定义方法,就子类就不能实例对象

         4)python中更推崇约定即【鸭子类型】,大家统一遵照就可以了,这样的好外是:可以不需要继承父类,即没有莲藕关系。

         5)鸭子类型:通过谚语来阐述:具体的功能不一样,但是功能名必须一样:例【鸭子类型之读写件】

    import abc
    class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def speak(self):
    pass

    class People(Animal):
    def speak(self):
    print('say:hi')

    class Dog(Animal):
    def speak(self):
    print('汪汪')

    class Pig(Animal):
    def speak(self):
    print('哼哼')

    obj1 = People()
    obj2 = Dog()
    obj3 = Pig()

    例【鸭子类型之读写件】:

    class Disk:
    def read(self):
    print('Disk read')

    def write(self):
    print('Disk write')


    class Cpu:
    def read(self):
    print('Cpu read')

    def write(self):
    print('Cpu write')


    class Memory:
    def read(self):
    print('Memory read')

    def write(self):
    print('Memory write')

    obj1 = Disk()
    obj2 = Memory()
    obj3 = Cpu()

    obj1.read()
    obj2.read()
    obj3.read()
  • 相关阅读:
    html中#include file的使用方法
    【leetcode】Next Permutation
    diameter
    android listview综合使用演示样例_结合数据库操作和listitem单击长按等事件处理
    【剑指offer】链表倒数第k个节点
    【经典面试题】实现平方根函数sqrt
    对CAB文件进行数字签名
    实习面试总结
    从队列、二叉树到优先队列
    句子的理解
  • 原文地址:https://www.cnblogs.com/qingqinxu/p/10884027.html
Copyright © 2011-2022 走看看