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):pass
class B(A):
def func(self):pass
class C(B):
def func(self):pass
class D(C):
def func(self):pass
d = 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: pass
class B(A): pass
class C(A): pass
class D(B): pass
class E(C): pass
class F(D, E): pass
C3算法
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, abstractmethod
class Payment(metaclass=ABCMeta): # 这是个抽象类
@abstractmethod
def pay(self, money):
pass
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名字发生变化的时候
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})
# 输出
abc
12345
[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:
pass
class 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.show
s2_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 f1
in A f2
in A f1
in 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 pickle
class 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个']
day-25-类的继承顺序-父类对子类的约束-多态-队列和栈的更多相关文章
- PAT 甲级 1074 Reversing Linked List (25 分)(链表部分逆置,结合使用双端队列和栈,其实使用vector更简单呐)
1074 Reversing Linked List (25 分) Given a constant K and a singly linked list L, you are supposed ...
- java中父类与子类, 不同的两个类中的因为构造函数由于递归调用导致栈溢出问题
/* 对于类中对成员变量的初始化和代码块中的代码全部都挪到了构造函数中, 并且是按照java源文件的初始化顺序依次对成员变量进行初始化的,而原构造函数中的代码则移到了构造函数的最后执行 */ impo ...
- 20141214--C#父类,子类
首要: 子类 包含父类的所有的属性方法 所有子类都可以直接转化成父类类型 当父类类型变量里面存的是某个子类的对象的时候,才能转化成那个子类类型. 父类与子类的装换: Ren r = new Ren() ...
- Java特性之多态父类与子类之间的调用
问题描述: Java三大特性,封装.继承.多态,一直没搞懂其中多态是什么,最近研究了一下,关于父类和子类之间的调用.下面是一个测试类,源代码如下: package com.test; public c ...
- Java 父类和子类
package chapter11; public class GeometricObject1 { private String color="white"; private b ...
- P188 实战练习(父类和子类)
1.创建一个父类,在父类中创建两个方法,在子类中覆盖第二个方法,为子类创建一个对象,将它向上转型到基类并调用这个方法. 创建Computer父类: package org.hanqi.practise ...
- C#基础知识—父类和子类的关系
基础知识一: using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms ...
- php 父类调用子类方法和成员
在C和C++里,父类都不允许调用子类的方法,但在php里可以.下面是一个调用的例子: <?php abstract class Animal { protected $name; public ...
- Java 多态 父类和子类方法的访问控制权限
Java 多态 父类和子类方法的访问控制权限 @author ixenos 父类和子类方法的访问控制权限 继承是为了扩展类的功能,而这种扩展显然就是对一个原始类的扩展,目的还是向上转型来调用,所以这就 ...
随机推荐
- 都学Python了,C++难道真的用不着了吗?
本文首发 | 公众号:lunvey 人人都在学Python,我还学C++吗? 现在只要提及编程语言,得到的答复都是:学Python,有未来! 大家可能有一个误区,数据分析带火了Python,让人们 ...
- Google单元测试框架gtest之官方sample笔记2--类型参数测试
gtest 提供了类型参数化测试方案,可以测试不同类型的数据接口,比如模板测试.可以定义参数类型列表,按照列表定义的类型,每个测试case都执行一遍. 本例中,定义了2种计算素数的类,一个是实时计算, ...
- Kubernetes: NGINX/PHP-FPM 502错误和优雅结束
我们有一个运行在Kubernetes上的PHP应用,每个POD由两个独立的容器组成 - Nginx和PHP-FPM. 在我们对应用进行缩容时,遇到了502错误,例如,当一个POD在结束中时,POD里面 ...
- AVR单片机教程——第三期导语
背景(一) 寒假里做了一个灯带控制器: 理想情况下我应该在一个星期内完成这个项目,但实际上它耗费了我几乎一整个寒假,因为涉及到很多未曾尝试的方案.在这种不是很赶时间的.可以自定目标.自由发挥的项目中, ...
- HDOJ-3416(最大流+最短路+ISAP算法+向前星dijikstra算法+如何判断一条边是否在最短路中)
Marriage Match IV HDOJ-3416 这题的题意就是要找两点之间最短路的路径个数,而且边不能重复. 最大流和最短路的结合.首先正向和反向建图,再跑两遍dijikstra.到这里就求出 ...
- HDOJ-1213(简单并查集)
How many tables HDOJ-1213 #include<iostream> #include<cstring> #include<cstdio> #i ...
- 精确率precession和召回率recall
假设有两类样本,A类和B类,我们要衡量分类器分类A的能力. 现在将所有样本输入分类器,分类器从中返回了一堆它认为属于A类的样本. 召回率:分类器认为属于A类的样本里,真正是A类的样本数,占样本集中所有 ...
- SpringBoot启动流程原理解析(二)
在上一章我们分析了SpingBoot启动流程中实例化SpingApplication的过程. return new SpringApplication(primarySources).run(args ...
- 在C++中实现aligned_malloc
malloc的默认行为 大家都知道C++中可以直接调用malloc请求内存被返回分配成功的内存指针,该指针指向的地址就是分配得到的内存的起始地址.比如下面的代码 int main() { void * ...
- 使用Webpack构建多页面程序
使用webpack搭建单页面程序十分常见,但在实际开发中我们可能还会有开发多页面程序的需求,因此我研究了一下如何使用webpack搭建多页面程序. 原理 将每个页面所在的文件夹都看作是一个单独的单页面 ...