一、继承
定义一个类时,需要使用另外一个类的方法或属性,就可以通过继承实现
object是Python的顶级类,创建类是会自动继承,就拥有object中的方法
- 定义格式
# 类的定义
# 旧式类定义 一般在定义单个类时使用
class 类名:
name = None
def func(self):
pass
# 新式类定义 一般在继承时使用
class 类名(指定需要继承的类):
name = None
def func(self):
pass
# 新式类定义
class A():
name = '张三'
def func(self):
# pass 不做处理
pass
# 旧式类
class B:
age = 20
def fucn(self):
pass
print(A.name)
print(B.age)
1-1 单继承
一次继承一个类
(1)Father类有一个性别属性,默认为男,同时,Father跑步速度快;(2)如果Son类也想要拥有这些属性和方法,该怎么做呢?
(3)执行程序,观察程序效果。
# 单继承 只继承一个类
class Father:
gender = '男'
def run(self):
print('跑步很快')
# 子类继承父类获取父类中属性和方法
class Son(Father):
# 定义子类的属性和方法
age = 20
def play(self):
print('玩游戏')
# 创建子类对象
s = Son()
# 使用子类对象操作父类的属性和方法以及自己的属性和方法
print(s.gender)
print(s.age)
s.run()
s.play()
(1)从前,有个摊煎饼的老师傅[Master],在煎饼果子界摸爬滚打多年,研发了一套精湛的摊煎饼(flapjack)技术;
(2)渐渐地,老师傅老了,就想着把这套技术传授给他唯一的最得意的徒弟[Apprentice];
(3)试着通过初始化、无参、定义方法与单继承来模拟程序。
# 单继承的使用
class Master:
name = '师父'
def flapjack(self):
print('摊鸡蛋煎饼')
class Apprentice(Master):
# 子类继承后可以不定义属性和方法,直接使用父类的方法
pass
a = Apprentice()
# 子类使用父类方法
a.flapjack()
1-2 多继承
继承多个类
(1)徒弟是个爱学习的好孩子,想学习更多的摊煎饼技术;(2)于是,在百度搜索到黑马程序员学校[School],报班来培训学习如何摊煎饼;
(3)使用多继承形式模拟程序。
# 单继承的使用
class Master:
name = '师父'
def flapjack(self):
print('摊鸡蛋煎饼')
class School:
name = '学校'
def flapjack(self):
print('摊肉肠煎饼')
class Apprentice(Master,School):
# 子类继承后可以不定义属性和方法,直接使用父类的方法
pass
a = Apprentice()
# 子类使用父类方法
a.flapjack()
# 查看子类的继承父类顺序
print(Apprentice.__mro__)
(1)可以发现老师傅[Master]、培训学校[School]都有摊煎饼方法;
(2)在徒弟对象中调用摊煎饼方法,会执行哪个父类的方法呢?
调用第一个父类的方法,print(Apprentice.
__mro__
) # 查看类的继承执行顺序(3)思考:当给父类培训学校[School]新增编程方法后,子类能调用方法吗?
多继承时,父类方法都能被继承,但是如果有相同方法名,则在执行方法时,会按照print(Apprentice.
__mro__
)显示的顺序查找方法执行如果想要能后执行所有父类方法,则需要将函数名字进行修改,避免函数名冲突
# 单继承的使用
class Master:
name = '师父'
def master_flapjack(self):
print('摊鸡蛋煎饼')
class School:
name = '学校'
def school_flapjack(self):
print('摊肉肠煎饼')
class Apprentice(School,Master):
# 子类继承后可以不定义属性和方法,直接使用父类的方法
pass
a = Apprentice()
# 子类使用父类方法
a.master_flapjack()
a.school_flapjack()
# 查看子类的继承父类顺序
print(Apprentice.__mro__)
1-3 方法重写
子类中定义了和父类相同的方法,就是对父类方法的重写,在执行方法时,使用的是子类的逻辑代码
(1)徒弟非常认真学习,终于掌握了老师傅的技术;(2)接着,自己潜心钻研出类独门配方的全新摊煎饼技术;
(3)使用方法重写对摊煎饼方法进行处理。
当对父类方法重写后,执行时只会执行子类的的方法逻辑,不会再执行父类方法中的逻辑
# 重写父类方法 子类继承父类后定义了一个和父类相同名字的方法
# 单继承的使用
class Master:
name = '师父'
def flapjack(self):
print('摊鸡蛋煎饼')
class Apprentice(Master):
# 子类中定义了自己方法,和父类方法名一样
# 子类相当于重写了父类的方法,在执行时按照子类的逻辑执行
def flapjack(self):
print('摊手抓饼')
a = Apprentice()
a.flapjack()
子类重写父类方法,在调用时执行的子类的逻辑,还想调用父类方方法,需要借助super()方法实现
(1)徒弟在培训学校学习努力,不仅掌握了黑马摊煎饼配方、还创办了自己煎饼果子的品牌;[配方、品牌]
(2)配合着一起摊煎饼,做出了更加美味的煎饼果子;
(3)使用调用父类方法在
__init__()
和摊煎饼方法中处理。
# 重写父类方法 子类继承父类后定义了一个和父类相同名字的方法
# 单继承的使用
class Master:
name = '师父'
def flapjack(self):
print('摊鸡蛋煎饼')
class Apprentice(Master):
# 子类中定义了自己方法,和父类方法名一样
# 子类相当于重写了父类的方法,在执行时按照子类的逻辑执行
def flapjack(self):
# 在子类中调用父类相同的方法 使用super()
# 通过super可以获取父类对象
print(super().name)
print('摊手抓饼')
super().flapjack()
a = Apprentice()
a.flapjack()
1-4 多层继承
(1)N年后,当初的徒弟也老了;
(2)因此,徒弟想要把"有自己品牌,也有黑马配方的煎饼果子"的所有技术传授给自己的小徒弟;
(3)请试着使用多层继承的方式完成案例。
# 多层继承
# 重写父类方法 子类继承父类后定义了一个和父类相同名字的方法
# 单继承的使用
class Master:
name = '师父'
def flapjack(self):
print('摊鸡蛋煎饼')
class Apprentice(Master):
name = '徒弟'
def flapjack(self):
print('摊手抓饼')
super().flapjack()
class LittleApprentice(Apprentice):
name = '小弟'
def flapjack(self):
print('蒸包子')
super().flapjack()
# 创建对象
la = LittleApprentice()
la.flapjack()
print(LittleApprentice.__mro__)
# 多层继承
# 重写父类方法 子类继承父类后定义了一个和父类相同名字的方法
# 单继承的使用
class Master:
name = '师父'
def flapjack(self):
print('摊鸡蛋煎饼')
class School:
name = '学校'
def school_flapjack(self):
print('摊肉肠煎饼')
class Apprentice(Master,School):
name = '徒弟'
def flapjack(self):
print('摊手抓饼')
super().flapjack()
class LittleApprentice(Apprentice):
name = '小弟'
def flapjack(self):
print('蒸包子')
super().flapjack()
# 创建对象
la = LittleApprentice()
la.flapjack()
la.school_flapjack()
print(LittleApprentice.__mro__)
二、多态
多态指的是一类事物的多中形态
相同的方法,产生不同的执行结果
运算符 + * 的多态
int + int 加法计算
str + str 字符串拼接
list + list 列表的数据合并
在python中可以使用类实现一个多态效果
在python中使用重写的方式实现多态(1)定义两个类:老师、车;
(2)定义老师类的属性:姓名,定义老师类的方法:开车、停车;
(3)定义车类的属性:类型,定义车类的方法:开启、停止;
(4)联系:老师开车,执行程序,观察效果;
# 多态
class Teacher:
def __init__(self,name):
self.name = name
def run(self):
print(f'{self.name}老师开车')
def stop(self):
print(f'{self.name}老师停车')
class Car:
def __init__(self,type):
self.type = type
def start(self):
print(f'{self.type}启动')
def close(self):
print(f'{self.type}熄火')
t = Teacher('张三')
c = Car('小汽车')
c.start()
t.run()
c.close()
t.stop()
使用继承方式,调整执行的方法
# 多态
class Teacher:
def __init__(self,name):
self.name = name
def run(self):
print(f'{self.name}老师开车')
def stop(self):
print(f'{self.name}老师停车')
class Car(Teacher):
def __init__(self,type,name):
super().__init__(name)
self.type = type
def start(self):
print(f'{self.type}启动')
super().run()
def close(self):
print(f'{self.type}熄火')
super().stop()
c = Car('小汽车','张三')
c.start()
c.close()
(5)思考:老师有可能开小轿车、骑自行车、坐地铁等,该怎么改进程序呢?
使用子类的重写功能实现多态
多态实现的流程1-定义一个父类,在父类中定义需要执行的业务方法,具体方法的逻辑不用实现,直接pass,由继承的子类实现
2-定义多个功能的子类继承父类,在子类中对父类方法重写,实现自己子类的逻辑
3-封装一个统一的函数处理方法,让开发人员调用该方法
# 多态
class Teacher:
def __init__(self,name):
self.name = name
def run(self):
pass
def stop(self):
pass
class Car(Teacher):
def __init__(self,type,name):
super().__init__(name)
self.type = type
def run(self):
# 在多态实现时,子类继承父类并对父类方法进行重写
print(f'{self.type}启动')
print(f'{self.name}老师开车')
def stop(self):
print(f'{self.type}熄火')
print(f'{self.name}老师停车')
class Metro(Teacher):
def __init__(self,type,name):
super().__init__(name)
self.type = type
def run(self):
# 在多态实现时,子类继承父类并对父类方法进行重写
print(f'{self.type}启动')
print(f'{self.name}老师乘坐地铁')
def stop(self):
print(f'{self.type}到站')
print(f'{self.name}老师下车')
# 单独封装一个行为函数
# 该函数就是对外提供一个函数接口,其他开发人员使用,就调用函数
def action(obj):
# obj接收一个对象
obj.run()
obj.stop()
c = Car('越野车','张三')
action(c)
m = Metro('地铁1号线','李四')
action(m)
三、文件读写
通过文件读写完成对文件数据的处理
使用python中open方法实现对文件的读写
-
格式
-
会返回一个文件描述符
-
使用文件描述符进行数据的读取或写入
-
f = open(文件位置,读写方式,文件读写格式(utf-8,gbk))
data = f.read() 读取
f.write(数据) 写入
f.close() 关闭文件
3-1 文件数据读取
# 文件数据读取
# 1-打开文件 创建文件描述符
# open的第一个参数指定读取的文件路径 可以使用绝对路径 也可以使用相对路径 windos的路径需要改斜杠
# 第二参数指定读写方式 r读 w写
# 第三个参数指定文件编码格式,方便读取中文数据 常用的两种utf-8 gbk
f = open('D/study/students.txt','r',encoding='utf-8')
# 读取数据文件
# 第一种 读取一行数据
# line_data1 = f.readline()
# print(line_data1)
# line_data2 = f.readline()
# print(line_data2)
# 第二种读取多行数据 将读取的多行数据放入列表中 该方式最常用
lines_data = f.readlines()
print(lines_data)
# 第三种 一次将所有数据读取出来当成一个完整的字符串数据 前面已经读取过数据 read就无法再读到数据 所以在实际开发中三种方式选择一种
# data = f.read()
# print(data)
# print(type(data))
# 数据取完成后可以使用close方法关闭文件
f.close()
3-2 数据写入文件
-
写入方式
-
w 覆盖写入数据
-
a 追加写入数据
-
-
写入类型
- 要求写入数据是字符串类型
# 文件数据写入
# 1-先打开文件获取文件描述符 文件描述符用来操作文件
# 使用相对路径 代码文件运行的所在路径
# csv文件是以逗号分割的数据文件 可以使用excel打开
# w是覆盖写入数据 a是追加写入数据
f = open('./data.csv','a',encoding='utf-8')
# 写入数据
f.write('3,王五,20,男')
f.write('\n') # 写入换行符 进行换行
f.write('4,赵六,22,男')
f.write('\n')
#关闭文件
f.close()
3-3 二进制文件读写
-
图片,视频,音频
- 在进行二进制文件数据读写时需要使用 rb ,wb
# 二进制文件数据读写
# 1-打开文件获取文件描述符
f = open('D/study/1.jpeg','rb')
# 使用read一次性全部读取
data = f.read()
print(data)
# 关闭文件
f.close()
# 打开新的文件,将图片数据保存
f2 = open('./2.jpeg','wb')
f2.write(data)
f2.close()
3-4 with open 语法 读写文件
可以帮助开发人员在文件读写完成自动调用close
# 使用with open自动关闭文件
with open('D/study/students.txt','r',encoding='utf-8') as f:
data = f.read()
print(data)
with open('data.json','w',encoding='utf-8') as f:
f.write('{"id":1,"name":"张三"}')
f.write('\n')
f.write('{"id":2,"name":"李四"}')
f.write('\n')
-
文件后缀
-
txt
-
csv
-
json
-
文件后缀和文件的数据本身没有直接关系
-
后缀只是为了说明可以使用那种工具打开该文件,方便识别文件类型
-
四、异常处理
在程序运行时出现的错误,使用对应方法时没有按照开发语言的要求使用
一旦出现错误,会中断代码的执行。
实际开发中需要对异常问题单独判断处理,保证程序能持续运行
捕获到异常后根据需求处理,也可以不处理
4-1 常见异常
索引错误
- 索引下标异常,一般发生在数据取值
字典key值错误
- key值错误 字典取值时错误
类型错误
- 类型错误 多个数据进行计算时或出现的问题
文件错误
- 读取文件时问价不存在
# 索引下标取值错误
data = 'itcast'
data[100]
# 字典取值错误
data = {'name':'张三'}
data['age']
# 类型错误
data = '100'
data2 = 10
data3 = data/data2
# 文件读取错误 路径不存在
with open('aaa.txt','r',encoding='utf-8') as f:
f.read()
4-2 异常捕获
通过语法捕获代码中的异常,根据异常信息,解决异常的问题,保证代码能持续运行
- 格式
try:
需要捕获遗产干的代码片段,有开发人员自己决定哪些代码需要捕获
except:
捕获到异常后处理的逻辑
# 进行异常捕获
try:
# 把出现的错误的代码逻辑放入try的作用域中
data = 15/0
except:
# 捕获到异常处理的业务逻辑
print('异常被捕获')
# 异常被捕获后,可以正常执行后续的逻辑
print('其他代码逻辑')
4-3 指定异常类型捕获
# 可以捕获所有异常
try:
data_str = 'itcast'
# data_str[100]
f = open('aasd.txt','r',encoding='utf-8')
except:
# 捕获到异常处理的业务逻辑
print('异常被捕获')
# 异常被捕获后,可以正常执行后续的逻辑
print('其他代码逻辑')
# 捕获固定的异常 处理固定错误
try:
# data = 15/0
# f = open('aasd.txt', 'r', encoding='utf-8')
data_str='itcast'
data_str[100]
# 捕获指定异常
except (FileNotFoundError,ZeroDivisionError,IndexError):
print('捕获0为除数的异常')
print('其他代码逻辑')
4-4 异常的其他处理
可以在处理异常时编写没有异常的逻辑
try:
data = 15/0
# Exception as e 获取异常的错误信息
# 可以捕获到异常后输出错误信息
except Exception as e:
print('异常被捕获')
print(e)
else:
print('else 没有异常逻辑')
finally:
print('finally :无论是否有异常都执行')
4-5 函数中的异常处理
- 在调用函数时进行异常捕获
def func(a,b):
data = a + b
print(data)
try:
# 调用其他开发人员编写的代码处理错误
func('10',20)
except Exception as e:
print(e)
- 封装函数时异常捕获
# 函数的异常处理
def func(a, b):
data = 0
# 在封装的函数内捕获异常
try:
data = a + b
except:
# 函数内自己处理异常
print('异常错误')
return data
# 调用函数
func(10,'20')
- 函数内捕获到异常不处理,再传递给掉用函数的地方
# 函数的异常处理
def func(a, b):
data = 0
# 在封装的函数内捕获异常
try:
data = a + b
except:
# 将异常的错误信息传递到调用地方 当前没有处理异常
raise Exception('函数内计算错误')
return data
# 调用函数时,捕获函数执行的异常
try:
func(10,'20')
except Exception as e:
print('异常捕获')
print(e)
# 多个函数中都要使用的变量可以定义成全局变量,通过global声明,就可在多个函数就可以共享全局数据
name_list = []
password_list = []
# 登录注册功能
def login():
# 函数作用域
# 通过四个空格,来确认函数所执行的逻辑从哪里开始
# 列表,元组,集合,字典数据可以省略global声明
15/0
global name_list
global password_list
for num in range(3): # [0,3) 0,1,2
name = input('请输入用户名:')
password = input('请输入密码:')
# 先判断用户名是否正确
if name in name_list:
# 在判断密码是否正确
if password in password_list:
print('登录成功')
# 适应break关键,会结束循环,不再进行取值
break
else:
print('密码不正确')
else:
print('用户名不正确')
def register():
global name_list
global password_list
name = input('请输入注册的用户名:')
password = input('请输入出注册的密码:')
# 将用户的名字和密码添加到全局的数据列表
name_list.append(name)
password_list.append(password)
while 1==1:
num = input('1-登录 2-注册 3-支付 4-下单 5-退出程序:')
if num == '1':
# 函数功能的调用
try:
login() # 函数名()
except:
print('登录出现错误')
elif num == '2':
register()
elif num == '3':
pass
elif num == '4':
pass
else:
break