day25 ( 多继承 , 组合 , 菱形继承 , 接口 , 抽象 , 鸭子类型 )

时间:2022-12-15 20:06:14

一, 复习

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

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

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

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

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

    class 子类(父类):
        pass

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

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

派生
    子类拥有与父类不同的内容
覆盖
    子类出现了与父类完全相同的名字

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


子类访问父类的内容
    1.指名道姓 直接写死了类名   即时不存在继承关系也能调用
    2.super().要访问的属性 (py3出现的)
    3.super(这个子类的名字,self).属性

 

二 , 继承已有的类来扩展新功能


#
实现一个存储类,在提供基本的存取功能之外,还要可以限制存储元素的类型 class MyList(list): def __init__(self,element_cls): #当你覆盖了init时,不要忘记调用super().init函数让父类完成原有的初始化操作 super().__init__() self.element_cls = element_cls def append(self,object): if object.__class__ == self.element_cls: #如果传进来的数据与我限制的的类型匹配上,则添加到列表 super().append(object) else: print('只能存储%s类型!'%self.element_cls.__name__) li = MyList(str) li.append(10) #只能存储str类型! li.append('123') print(li) #['123']

 

三 , 多继承问题

class A:
    def test(self):
        print('from A')
        super().test()      #应该报错,但是执行成功了

class B:
    def test(self):
        print('from B')


class C(A,B):
    pass

c = C()
c.test()
# from A
# from B

print(C.mro())  #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

#问题:多继承时如果多个父类中出现了同名的属性/函数
#你不能用眼睛去判断查找顺序,需要使用mro列表去查看真正的继承顺序
#总结:super在访问父类属性时,是按照mro列表一层层往上找的

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

aa = E()
print(aa.a)
print(E.mro())  #[<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]

 

四  , 组合

'''
组合:
    指的是一个类把另一个类作为自己的属性来使用,就称之为组合
    当你定义一个类,并且这个类拥有某种类型的属性时,就称之为组合
    
组合描述的是:什么拥有什么的关系,  学生有书  学生有手机
继承描述的是:什么是什么的关系   麦兜是猪  猪猪侠也是猪
'''''

class PC:
    def open_app(self,app_name):
        print('open %s'% app_name)

class Student:
    def __init__(self,PC,notbook):
        self.PC = PC
        self.notbook = notbook


pc = PC()
notbook = PC()

s = Student(pc,notbook)
s.PC.open_app('qq')
s.notbook.open_app('what')
# s.PC.open_app('ch')

 

五 , 菱形继承

# 在py2中 A就是一个经典类
# class A:
#     pass

# 如果你的代码需要兼容py2 那应该显式的继承object  无论是直接还是间接继承
class B(object):
    pass

class A(B):
    pass

 

六 , 接口

'''
接口:就是一套协议规范
具体表现形式:有一堆函数,但是只明确了函数的名称,没有明确函数的具体表现
'''''

import  abc

class USB(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def open(self):
        pass
    @abc.abstractmethod
    def work(self):
        pass
    @abc.abstractmethod
    def close(self):
        pass


class Mouse(USB):
    #实现接口规定的所有功能
    def open(self):
        print('mouse open')

    def work(self):
        print('mouse word')

    def close(self):
        print('mouse close')

class KeyBord:
    def open(self):
        print('KeyBoard open')

    def work(self):
        print("KeyBoard working...")

    def close(self):
        print("KeyBoard closed")
#问题是无法限制子类,必须真正的实现接口中的功能 class Camera(USB): def open(self): pass def work(self): pass def close(self): pass class PC: def device(self,usb_device): usb_device.open() usb_device.work() usb_device.close() #在实例化Camera abc模块就会检查Camera是否实现了所有的抽象方法,如果没有则无法实例化 c = Camera() p = PC() #创建一个鼠标设备 m = Mouse() #创建一个键盘设备 key1 = KeyBord() #链接到电脑上 p.device(m) p.device(key1) p.device(c)

 

七 , 抽象

'''
抽象类:具备抽象方法的类
抽象方法是,没有函数体的方法
抽象类的特点:不能直接实例化
'''''

import abc
class Test(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def say_hi(self):
        pass

    #可以有普通函数
    def info(self):
        print('my class is Test')

class TT(Test):
    def say_hi(self):
        print('i an TT obj')
    # pass


t = TT()
t.info()
t.say_hi()

 

八 , 鸭子类型

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)

 

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,"一个数据...")