python25 1.继承的另一种使用方式 2.super()的问题 mro列表 3.组合 4.菱形的继承问题 5.接口 6.抽象类 7.鸭子类型

复习


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

3.绑定方法
指的是 将类或对象与函数进行了绑定
之所以绑定是为了提高整合度,后续在拿到对象就可以直接调用而无需关心 数据是什么 如何处理
对象也可以看做是一个存储数据的容器

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

5.继承
说的是类与类之间的关系
存在基础关系后 子类可以直接使用父类已经存在的内容 总的来说是为了提高代码的复用性
例如猫 和狗 都属于动物类
描述的是 什么是什么的关系 如:猫是动物

要开始累积自己的类库 把经常使用的小功能写到一个模块中 以后可以直接调用

class 子类(父类):
pass

6.属性查找顺序
对象本身 -> 所在的类 -> 类的父类 -> .... object

7.抽象
使用基础时 应该先抽象 在继承
抽象指的是 把一系列类中的相同的特征和行为抽取 形成一个新的类 (公共父类)
8.派生与覆盖
派生
子类拥有与父类不同的内容
覆盖
子类出现了与父类完全相同的名字

9.一切皆对象
在py3里面所有东西全是对象 包括 int list 模块 函数 .....包等等....
list.append(li,1)


10.子类访问父类的内容
1.指名道姓 直接写死了类名 即时不存在继承关系也能调用
2.super().要访问的属性 (py3出现的)
3.super(这个子类的名字,self).属性
 
 
今日内容
 
1.继承的另一种使用方式
2.super()的问题  mro列表
3.组合
4.菱形的继承问题
5.接口
6.抽象类
7.鸭子类型
 
 
 
 
# 1.继承的另一种使用方式   `*****`
   1.1通常:      最常见的是直接继承一个已经存在的类
1.2另一种使用方式:
                 当你想要创建一个新的类 发现这个类中的一些 在某一个类中已经存在
                  那就没有必要从头开始写 ,可以直接继承已有的类 然后做补充
 案列:
class MyList(list):
    def __init__(self,element_cls):
        # 当你覆盖了init方法时
        # 不要忘记调用super().init函数让父类完成原有的初始化操作
        super().__init__()
        self.element_cls = element_cls
       
    def append(self, object):
          #判定类型的两种方法:
        # if isinstance(object,str)#方法一
        if object.__class__ == self.element_cls:#方法二
            super().append(object)
        else:
            print("只能存储%s类型!" % self.element_cls.__name__)
p=MyList(int)
p.append(1)
print(p)
#值[1]
```
 
2.super()的问题  mro列表 
 
    2.1python支持多继承  一个类可以同时继承多个父类
    2.2好处是更加灵活
    2.3问题是:属性的查找顺序该怎么确定 
           # 问题:多继承时如果多个父类中出现了同名的属性/函数
           # 你不能用眼睛去判断查找顺序 ,需要使用mro列表来查看真正的继承顺序
           # 总结:super在访问父类属性时 是按照mro列表一层层往上找的
#测试
class A:
    def test(self):
        print("from A")
        super().test() # 应该报错..... 但是却执行成功了
class B:
    def test(self):
        print("from B")
    pass
class C(A,B):
    pass
c = C()
c.test()
2.4#值--->super()的问题  :python支持多继承  一个类可以同时继承多个父类
from A
from B
2.5#mro列表 
print(C.mro())
#值表示调用顺序[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
#最后:尽量不要使用多继承
```
3.#组合:

组合:      指的是 一个类把另一个类的对象作为自己的属性 就称之为组合
无处不在
 
             当你定义一个类 并且这个类拥有某种类型的属性时 就称之为组合
用途:
              都是用用来重用代码的方式:
组合与继承对比:

         组合描述的是 : 什么拥有什么的关系   学生 有 书  学生有手机
         继承描述的是 : 什么是什么的关系      麦兜是猪    猪猪侠也是猪
"""

# class Person:
#     def __init__(self,name):
#         self.name = name
#
#
# p = Person("rose")
# print(p.name)

class PC:
    def open_app(self,app_name):
        print("open %s" % app_name)
class OldBoyStudent:
    def __init__(self,PC,notebook):
        self.PC = PC
        self.notebook = notebook
    pass
pc = PC()
notebook = PC()

stu = OldBoyStudent(pc,notebook)
```
4.菱形继承问题  ***
  菱形继承:------如果无菱形,深度优先
 4.1 概念:一个类有多个父类,并且多个父类之间又同时继承另一个父类,就产生了,菱形继承
 
4.2新式类与经典类
经典类:旧版,没有继承自object的类,统称为经典类 ,只出现在便宜中
新式类:直接或间接继承了object的类就是新式类,py3全都是新式类

4.2.1# 在py2中 A就是一个经典类——>没有mro列表
# class A:
#     pass
print(A.__class__)
print(type(A))
值:
<class 'type'>
<class 'type'>
Process finished with exit code 0
4.2.2# 如果你的代码需要兼容py2 那应该显式的继承object  无论是直接还是间接继承
案例:
class B(object):
    pass
class A(B):
    pass
```
 
class A:
    # a = 1
    pass
class B(A):
    # a = 2
    pass
class C(A):
    # a = 3
    pass
class D(A):
    # a = 4
    pass
class E(B,C,D):
    # a = 5
    pass
e1 = E()
# print(e1.a)
# 新式类的顺序
# E  B C D A object
# 经典类的顺序
# E B A C D
# print(E.mro())
注意:经典类没有mro列表
```
 4.3属性查找顺序:
如果出现菱形继承,
         经典类:在经典类中是深度优先
         新式类:由C3算法来确定继承顺序,先深度再广度,C3算法适用于属性查找顺序,通过mro()列表可以查到(print(E.mro()))
 
5# .接口 ***
5.1# 接口是什么 ?--一套协议规范
 
例如USB  
电脑内部具备USB相应的功能 如果要使用的话   就必须给外界提供一个使用方式,该方式就称之为接口 ,
 
在程序中功能通常是用函数来表示, 对于外界而言 无需清楚函数时如何实现的 只要知道函数名即可, 这个函数名称就可以称之为接口 
外界调用接口就能完成某个任务
 
接口其实就是一组功能的定义,但是只清楚函数名称,而没有具体的实现细节
相当于是一套规范,
 
例如USB
       规定了接口的外观,大小,以及每条线路的功能是什么
       硬件开发商照着这个USB协议来生产设备,就可以被电脑使用
 
具体表现形式:有一堆函数,但是只明确了函数的名称,没有明确函数具体怎么实现。
```
class USB:
    def open(self):
        pass
    def close(self):
        pass
    def work(self):
        pass
```
5.2好处:
          使用接口可以提高程序的扩展性
          只要对象按照接口规定方法来实现,使用者就可以无差别使用所有对象
5.3问题:无法限制子类,必须真正实现接口层的功能
 
6.抽象:
​       指的是 不清楚 不具体 看不懂
6.1 抽象方法:
​          指的是 没有函数体的方法   用@abc.abstractmethod 装饰器
​          如果类中具备抽象方法 那么这个类就称之为抽象类
6.2 抽象类的特点:
​        不能直接实例化  必须有子类覆盖了所有抽象方法后才能实例化子类
6.3 与接口的区别:
​        接口是指:只有方法声明而没有实现体 ,  接口中所有方法都是抽象的
```
import abc
class Test(metaclass=abc.ABCMeta):#源类
    @abc.abstractmethod
    def say_hi(self):
        pass
class TT(Test):
    def say_hi(self):
        print("i am TT obj")
t = TT()
t.say_hi()
```
 
6.4问题:如果接口的子类没有实现接口中的方法,那是没有任何意义的
6.5抽象类之所以出现的意义:
                              通过抽象类来强行限制子类必须覆盖所有的抽象方法
 
7.# 鸭子类型
说如果一个对象叫声像鸭子,走路像鸭子,长得像鸭子,那它就是鸭子
是python 推荐的方式,python不喜欢强行限制你
```
案例1
class PC():
    def conntent_device(self, usb_device):
        usb_device.open()
        usb_device.work()
        usb_device.close()
class Mouse:
    # 实现接口规定的所有功能
    def open(self):
        print("mouse opened")
    def work(self):
        print("mouse working...")
    def close(self):
        print("mouse closed")
mouse = Mouse()
pc = PC()
pc.conntent_device(mouse)
 
 
class KeyBoard:
    def open(self):
        print("KeyBoard opened")
    def work(self):
        print("KeyBoard working...")
    def close(self):
        print("KeyBoard closed")
key1 = KeyBoard()
# 如果key1的特征和行为都像USB设备 那就把它当做USB设备来使用
# 对于使用者而言可以不用关心这个对象是什么类,是如如何是实现,
pc.conntent_device(key1)
```
 
案例2:
```
class Linux:
    def read_data(self,device):
        data = device.read()
        return data
    def write_data(self,device,data):
        device.write(data)
class Disk:
    def read(self):
        print("disk reading....")
        return "这是一个磁盘上的数据"
    def write(self,data):
        print("disk writing %s..." % data)
class UP:
    def read(self):
        print("disk reading....")
        return "这是一个U盘上的数据"
    def write(self,data):
        print("disk writing %s..." % data)

l = Linux()
d = Disk()
data = l.read_data(d)
l.write_data(d,"这是一个数据....")

up1 = UP()
l.read_data(up1)
l.write_data(up1,"一个数据...")
```
例如linux 有一句话叫一切皆文件
之所以这么设计是为了提高扩展性,让Linux可以无差别对待任何设备!
 
 
 总结
 
今日的知识点:
1.继承的另一种使用方法
​               继承一个已经存在的类 并扩展新方法  或修改原来的方法
2.super()(是子类直接调用父类的一种方式) 是按照mro列表来查找属性的(给super按先后顺序求值)
3.组合  一个类把另一个类的对象作为属性
4. 菱形继承的问题
  
   经典类:不是object的子类   仅在py2中出现
   ​ 深度优先
   新式类:object的子类 py3中都是新式类
   ​ 先深度 直到有一个公共父类时,查找其他路线(基于C3算法)
5.接口是一套协议规范,具体表现:一堆只有方法声明而没有实现体的方法 
6.抽象类:具备抽象方法的类  抽象方法时没有实现体的方法   不能直接实例化  通过abc模块来实现 (限制)
抽象类既可以有抽象方法也可以有普通方法
而接口中全都是抽象方法 
接口的出现是为了提高扩展性,抽象类是为了限制子类必须按照接口要求的来实现
7.鸭子类型
对于一个优秀的程序员,即时没有接口和抽象类的限制,也能写出一个具备扩展性的程序
如何做到:  鸭子类型 
           鸭子类型:这个对象 长的想鸭子 叫声像鸭子 走路像鸭子  那它就是鸭子
          就可以把它当成鸭子来使用
 
 
 
 
 
原文地址:https://www.cnblogs.com/llx--20190411/p/10881258.html