阅读 123

day-25-类的继承顺序-父类对子类的约束-多态-队列和栈

一、类的继承顺序

只要继承object类就是新式类

不继承object类的都是经典类

 

在python3 中所有的类都继承object类,都是新式类

在python2 中不继承object的类都是经典类

继承object类的就是新式类

 

经典类:在py3中不存在,在py2中不主动继承object类

 

  • 在py2 中

    • class A:pass ——> 经典类

    • class B(object):pass ——> 新式类

  • 在py3 中

    • class A:pass ——> 新式类

    • class B(object):pass ——> 新式类

在单继承方面(无论是新式类还是经典类都是一样的)

用的是深度优先方法

寻找某一个方法的顺序是:D-->C-->B-->A

越往父类走,是深度

复制代码

class A:    def func(self):passclass B(A):    def func(self):passclass C(B):    def func(self):passclass D(C):    def func(self):passd = D()

复制代码

 

多继承方面

  • 广度优先——>在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,在走深度

  • 在经典类中,都是深度优先,总是在一条路走不通之后在换一条路,走过的点不会在走了

  • 在新式类中有 mro() ,可以查看寻找顺序

复制代码

class A:    def func(self):        print('A')class B(A):    def func(self):        print('B')class C(A):    def func(self):        print('C')class D(B,C):    def func(self):        print('D')
        
d = D()
d.func()print(D.mro())   # 只有在新式类中有,经典类没有# 输出D
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

复制代码

 

  • C3算法:

如果是单继承:那么总是按照从子类——>父类的顺序来计算查找顺序。

如果是多继承:需要按照自己本类,父类1的继承顺序,父类2的继承顺序.......

merge的规则(C3):

1、如果一个类出现在从左侧到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序的中的一个

2、或 一个类出现在从左侧到右顺序的最左侧, 并没有在其他顺序中出现 ,那么先提出来作为继承顺序的中的一个

3、如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类

在多继承中:经典类——>是深度优先

新式类——>是广度优先,遵循C3算法,可以用mro()查看顺序

复制代码

class A: passclass B(A): passclass C(A): passclass D(B): passclass E(C): passclass F(D, E): passC3算法
A(O) = [AO]     ——>A的继承关系 (O==>object)
B(A) = [BAO]    ——>B的继承关系
C(A) = [CAO]    ——>C的继承关系
D(B) = [DBAO]   ——>D的继承关系
E(C) = [ECAO]   ——>E的继承关系
F(D,E)  = merge(D(B) + E(C))    ——>F的继承关系

继承顺序  = [F] + [DBAO] + [ECAO]  ——>自己类加上两个父类的继承顺序
      F  = [DBAO] + [ECAO]      ——>取出左侧第一个F(条件右侧没有F)
     FD  = [BAO] + [ECAO]       ——>取出左侧第一个D(条件右侧没有D)
    FDB  = [AO] + [ECAO]        ——>左侧第一个A,右侧有A,跳过取右侧第一个E
   FDBE  = [AO] + [CAO]         ——>同上取右侧第一个C
  FDBEC  = [AO] + [AO]          ——>两边都是相同的取第一个A
 FDBECA  = [O] + [O]            ——>同上在取第一个O
FDBECAO     ——>最终继承顺序

复制代码

 

二、父类对子类的约束

抽象类:是一个开发的规范,约束它的所有子类必须实现一些和它同名的方法

列如:支付程序。

  • 微信支付 URL链接,告诉你参数什么格式

    • { ' username ' : ' 用户名 ' , ' money ' : 200 }

  • 支付宝支付 URL链接,告诉你参数什么格式

    • { ' uname ' : ' 用户名 ' , ' price' : 200 }

方法一:

复制代码

class Payment:  # 这是个抽象类
    def pay(self, money):        '''
        只要你见到了项目中有这种类,你要知道你的子类中必须实现和pay同名的方法        '''
        raise NotImplementedError('请在类中重写重名pay类方法') # 主动抛异常class WeChat(Payment):    def __init__(self, username):
        self.username = username    def pay(self, money):  # pay方法名字不能改变
        dic = {'username': self.username, 'money': money}        '''
        调用微信支付 url连接 把dic传过去        '''
        print(f'{self.username}通过微信充值了{money}')class Alipay(Payment):    def __init__(self, username):
        self.username = username    def pay1(self, money):
        dic = {'uname': self.username, 'price': money}        ''''
        调用支付宝支付 url连接 把dic传过去        '''
        print(f'{self.username}通过支付宝充值了{money}')# 归一化设计:同事或用户使用此类时,直接调用pay函数传参,不用自己创建对象def pay(username, money, kind):    if kind == 'WeChat':
        obj = WeChat(username)    elif kind == 'Alipay':
        obj = Alipay(username)
    obj.pay(money)

pay('小杨', 200, 'WeChat')# 当支付宝的pay方法名字发生改变时pay('小杨', 200, 'Alipay')# 输出小杨通过微信充值了200
报错:NotImplementedError: 请在类中重写重名pay类方法

复制代码

 

方法二:实现抽象类的另一种方式,约束力强,依赖abc模块

复制代码

from abc import ABCMeta, abstractmethodclass Payment(metaclass=ABCMeta):  # 这是个抽象类    @abstractmethod    def pay(self, money):        passclass WeChat(Payment):    def __init__(self, username):
        self.username = username    def pay(self, money):  # pay方法名字不能改变
        dic = {'username': self.username, 'money': money}        '''
        调用微信支付 url连接 把dic传过去        '''
        print(f'{self.username}通过微信充值了{money}')class Alipay(Payment):    def __init__(self, username):
        self.username = username    def pay1(self, money):
        dic = {'uname': self.username, 'price': money}        ''''
        调用支付宝支付 url连接 把dic传过去        '''
        print(f'{self.username}通过支付宝充值了{money}')# 当支付宝的pay名字发生变化的时候Alipay('xiao')      # 这种方法在实例化对象的时候就会报错提示# 输出TypeError: Can't instantiate abstract class Alipay with abstract method pay

复制代码

 

三、多态

一个类型表现出来的多种状态:

  • 同一个对象,多种形态。python默认支持多态

复制代码

def func(count):        # 这里的count可以是str、int、list、dict等等....count就是多态的
    print(count)


func('abc')
func(12345)
func([1, 2, 3, 4])
func({'a': 1, 'b': 2})# 输出abc12345[1, 2, 3, 4]
{'a': 1, 'b': 2}

复制代码

 

而在Java的情况下:

  • 一个参数必须指定类型

  • 所以如果想两个类型的对象都可以传,那么必须让着两个继承自一个父类,在指定类型的时候使用父类来指定

  • 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。

def func(int a):    print('a必须是数学')

 

  • 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。

def func(a):    print('a是什么都可以')

 

python伪代码实现Java或C的多态

复制代码

class F1:    passclass S1(F1):    
    def show(self):        print 'S1.show'class S2(F1):    
    def show(self):        print 'S2.show'# 由于在Java或C#中定义函数参数时,必须指定参数的类型# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类# 而实际传入的参数是:S1对象和S2对象def Func(F1 obj):"""Func函数需要接收一个F1类型或者F1子类的类型"""

    print obj.show()
    

s1_obj = S1()
Func(s1_obj)  # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.shows2_obj = S2()
Func(s2_obj)  # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show

复制代码

 

鸭子类型

在python中,有一句谚语,你看起来像鸭子,那么你就是鸭子。

对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。

比如:str、tuple、list 都有index方法,这就是互称为鸭子类型

复制代码

class A:    def f1(self):        print('in A f1')    
    def f2(self):        print('in A f2')class B:    def f1(self):        print('in A f1')    
    def f2(self):        print('in A f2')
        
obj = A()
obj.f1()
obj.f2()

obj2 = B()
obj2.f1()
obj2.f2()# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。# 输出in A f1in A f2in A f1in A f2

复制代码

 

四、队列和栈、自定义Pickle

内置的数据结构:

  • {}:——key-value 通过key找v非常快

  • []:——序列 通过index取值非常快

  • ():——元组

  • {1,}:——集合

  • 'abc':——字符串

不是python内置的:

  • Queue 队列:先进先出 FIFO (FIRST IN FIRST OUT)

    • put:进

    • get:出

  • Stack 栈:后进先出 LIFO (LAST IN FIRST OUT)

    • put:进

    • get:出

复制代码

class My_List:    def __init__(self):
        self.ll = []    def put(self, count):
        self.ll.append(count)class Stack(My_List):    def get(self):        return self.ll.pop()class Queue(My_List):    def get(self):        return self.ll.pop(0)


q = Queue()

s = Stack()for a in range(10):
    q.put(a)
    s.put(a)print('队列放进去的值:', q.ll)print('第一次取出:   ', q.get())print('第二次取出:   ', q.get())print('队列所剩值:   ', q.ll)print('------------------------------------')print('栈放进去的值: ', s.ll)print('第一次取出:   ', s.get())print('第二次取出:   ', s.get())print('栈所剩值:     ', s.ll)# 输出队列放进去的值: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
第一次取出:    0
第二次取出:    1队列所剩值:    [2, 3, 4, 5, 6, 7, 8, 9]------------------------------------栈放进去的值:  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
第一次取出:    9第二次取出:    8栈所剩值:     [0, 1, 2, 3, 4, 5, 6, 7]

复制代码

 

自定义Pickle,借助pickle模块来完成简化的dump和load

  • pickle dump

    • 打开文件

    • 把数据dump到文件里

  • pickle load

    • 打开文件

    • 读数据

对象 = Mypickle('文件路径')

对象.load() 能拿到这个文件中所有的对象

对象.dump(要写入文件的对象)

复制代码

import pickleclass Mypickle:    def __init__(self, path):
        self.path_ = path    def myload(self):
        with open(self.path_, mode='rb') as f1:            while True:                try:                    # 让读取到的数据变成迭代器
                    yield pickle.load(f1)                except EOFError:                    break

    def mydump(self, count):
        with open(self.path_, mode='ab') as f2:
            pickle.dump(count, f2)# 需要放入文件的数据ll = [f'第{a}个' for a in range(3)]# 实例化一个对象obj = Mypickle(r'my_obj')
obj.mydump(ll)      # 写入文件obj.myload()        # 读取文件的数据# 可以用__next__一条一条的读,也可以for循环读a = obj.myload().__next__()print(a)print('------------------------')# for循环读取迭代器内的数据for a in obj.myload():  
    print(a)    
# 输出['第0个', '第1个', '第2个']------------------------['第0个', '第1个', '第2个']
['第0个', '第1个', '第2个']
['第0个', '第1个', '第2个']

来源:https://www.cnblogs.com/XiaoYang-sir/p/14727845.html

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐