day19
1.python中的异常处理机制
"""
代码本身即便没有问题,但在运行的时候可能因为外部环境或资源的问题,导致代码无法运行,程序出现异常状况,如果异常状况没有处理,那么程序就会崩溃,具体表现就是代码停止运行。如果不希望程序崩溃,就要对代码进行异常状况的处理,在python中,可以使用try语法将可能出现状况的代码保护起来,在出现状况的时候,使用except进行异常状况的捕获,并给出相应的处理
注意:如果程序没有发生状况,except都不会执行
可以通过将except FileNotFoundError as err:将异常别名为err,通过err对象就可以获取关于异常的各种信息
"""
# 没有readme.txt这个文件时
import time
import sys
while True:
# 用try把可能出现状况的代码保护起来执行
try:
with open('readme.txt') as file:
print(file.read()) # FileNotFoundError: [Errno 2] No such file or directory: 'readme.txt'
break # 如果文件存在正常执行后就跳出循环
except FileNotFoundError: # 对号入座,如果文件找不到,此处就会进行异常捕获
print('文件不存在,5秒钟之后重新尝试读取该文件')
time.sleep(5)
except IOError: # # 对号入座,如果读文件发生了问题,此处会进行异常捕获
print('错误提示:读取文件失败,请确认设备是否就绪')
sys.exit(1) # 关掉python解释器
# 在实际项目开发中,这里要通过日志记录问题,可能还会通过网络异常反馈给开发者(需要网络支持)
except Exception: # 如果前面两个都没能对号入座,出现其他问题时就用Exception进行异常捕获
print('错误提示:程序发生了一点小问题,请拨打1110-123寻求帮助')
sys.exit(1) # 程序直接退出
finally: # 实际项目中,此处通常用来释放外部资源(例如网络连接,数据库连接等),因为这里的代码在任何情况下一定会被执行到,我们把这里称为总是执行代码,但在这里不会,因为在while True循环中不会结束
print('这个地方最适合释放外部资源')
print('程序结束!!!')
# 异常关键字:try, except, finally, raise
# raise关键字,抛出一个异常,引出一个异常
2.多态
"""
override - 重写/覆盖/置换 -> 子类将父类已有的方法重新实现一遍
子类继承父类的方法后,子类还可以重写父类的方法(重新实现该方法),不同的子类可以对父类的同一个方法给出不同的实现版本,这样方法在程序运行时就会表现出多态行为(调用相同的方法,做了不同的事情)
多态 - 不同的对象接收到相同的消息做了不同的事情
"""
"""
例子:给员工结算工资的系统:
公司有三类员工,结算工资的方式是不一样的
部门经理:15000元/月
程序员:计算工时 200元/时 * 本月工时
销售员:底薪 + 提成 1800元 + 本月销售额的5%的提成
给出员工的信息,自动结算员工月薪
员工:employee, 雇主:employer 薪水:salary 部门经理:manager 程序员:programmer 销售员:salesman
"""
# 抽象类,让Employee不能创建对象,抽象类:类名(mateclass=ABCmeta)
from abc import ABCmeta, abctractmethod # abc- 抽象
class Employee():
def __init(self, name):
self.name = name
@abctractmethod # 告诉子类重写实现该方法
def get_salary(self):
pass # 因为员工的薪资计算方式不同所以需要在子类中重写该方法
class Manger(Employee):
def __init__(self, name):
super().__init__(name)
def get_salary(self):
return 15000
class Programmer(Employee):
def __init__(self, name):
super().__init__(name)
self.working_hour = 0
def get_salary(self):
return 200 * self.working_hour
class Salesman(Employee):
def __init__(self, name):
super().__init__(name)
self.sales = 0.0
def get_salary(self):
return 1800 + self.sales * 0.05
# 实现多态(不同的人的薪资不同)
def main():
emps = [
Manger('曹操'), Programmer('荀彧'), Programmer('郭嘉'),
Salesman('典韦'), Salesman('曹仁'), Programmer('李典')
]
for emp in emps:
if type(emp) == Programmer:
emp.working_hour = int(input(f'请输入{emp.name}的工作时间:'))
elif type(emp) == Salesman:
emp.sales = float(input(f'请输入{emp.name}的本月销售额:'))
print(f'{emp.name}的工资为:{emp.get_salary()}元')
if __name__ == '__main__':
main()
# 练习:写一个分数类
"""
属性:分子,分母
方法:加法、减法、乘法、除法
相关单词:
分数 - fraction
分子 - numerator
分母 - denominator
add / substract / multiply / divide
"""
def gcd(x, y):
while y % x != 0:
x, y = y % x, x
return x
# 自定义异常类型通常直接继承Exception类或者它的子类,通过继承Exception自定义异常类型:自定义异常类型通常里面不用写什么代码,主要就是定义一种新的自定义类型来标记特殊的异常状况,代码直接复用Exception的代码
class FractionException(Exception):
pass
class Fraction:
# 除了用构造器语法,也可以使用类方法类创建对象
@classmathod
def from_value(cls, value: float, base=10000):
"""
将小数转换成分数
:param value: 要转换的小数
:param base: 倍数
:return: 类对象
"""
return cls(int(value * base), base)
@classmathod
def from_string(cls, string:str):
"""
将字符串转换成分数
:param string: 字符串
:return: 类对象
"""
items = string.split('/')
num, den = [int(item.split()) for item in items]
return cls(num, den)
def __init__(self, nem, den):
"""
初始化方法
:param num:分子
:param den:分母
"""
# 如果分母为0,直接引发异常让程序崩溃
# 通过raise关键字,引发异常,后面跟上异常对象来引发异常,如果使用这个代码的人没有做异常处理,那么程序就会在者个地方崩溃
if den == 0:
raise FractionException('分母不能为0')
self.num = num
self.den = den
self.simplay()
self.normalize()
def __str__(self):
"""
格式化输出
:return: f'{self.num}/{self.den}'
"""
if self.den == 1:
return f'{self.num}'
return f'{self.num}/{self.den}'
def simplay(self):
"""化简"""
# abs(数) - 求一个数的绝对值
factor = gcd(abs(self.num), abs(self.den)) # 调用gcd函数求分子和分母的最大公约数
self.num, self.den = self.num // factor, self.den // factor
return self
def normalize(self):
"""规范化"""
if self.num == 0:
self.den = 1
elif self.den < 0:
self.den = -self.den
self.num = -self.num
return self
# 魔法方法 里面写自己的加法运算代码,创建对象时直接可以用运算符‘+’进行分数之间的加法运算
def __add__(self, other):
num = self.num * other.den + self.den * other.num
den = self.den * self.num
return Fraction(num, den)
# 魔法方法 里面写自己的加法运算代码,创建对象时直接可以用运算符‘-’进行分数之间的加法运算
def __sub__(self, other):
num = self.num * other.den - self.den * other.num
den = self..den * other.den
return Fraction(num, den)
# 魔法方法 里面写自己的加法运算代码,创建对象时直接可以用运算符‘x’进行分数之间的加法运算
def __mul__(self, other):
num = self.num * other.num
den = self.den * other.den
return Fraction(num, den)
# 魔法方法 里面写自己的加法运算代码,创建对象时直接可以用运算符‘/’进行分数之间的加法运算
def__truediv__(self, other):
num = self.num * other.den
den = self.den * other.num
return Fraction(num, den)
#计算属性:通过对象现有的属性运算得到的一个值,本来是一个方法,但是我们可以通过添加@property装饰器,转换成属性处理
@property # @property会将value方法变为一个属性,调用的时候不用加小括号,直接调用
# 注意:一般没有参数的方法可以加@property,将其变为属性
def value(self):
"""将分数变为小数"""
return self.num / self.den
s1 = Fraction(1, 2)
s2 = Fraction(3, 4)
f1 = Fraction(-6, -9)
print(f1)
print(s1 + s2 + f1)
print((s1 + s2) * f1 / s1)
s1 *= s2
print(s1)
f2 = Fraction.from_string('6 / 9')
print(f2)
f3 = Fraction.from_value(0.75)
print('f3', f3)