一. 类的约束
约束程序的结构, 在分配任务之前就应该把功能定义好, 然后分别交给底下的程序员来完成相应的功能
在python中有两种办法来解决这样的问题
1. 提取父类, 然后在父类中定义好方法, 在方法中抛出一个异常, 这样所有继承父类的子类都必须重写这个方法, 否则访问的时候就会报错
class Base:
def login(self):
raise NotImplementedError # 没有被实现错误, 要求子类必须重写login方法 , 不然抛出异常
class User(Base):
def login(self):
print("用户登陆")
class UserManager(Base):
def login(self):
print("用户管理员登陆")
class Coder(Base):
def login(self):
print("后台程序员登陆")
def func(obj):
obj.login()
u = User()
um = UserManager()
c = Coder()
func(u)
func(um)
func(c)
2. 使用元类来描述父类, 在元类中给出一个抽象方法, 这样子类就不得不给出抽象方法的具体实现, 也可以起到约束的效果, 也就是子类必须重写该方法使之不在抽象, 就可以创建对象了
from abc import ABCMeta, abstractmethod
class Animal(metaclass = ABCMeta):
@abstractmethod
def eat(self):
print("吃什么")
class Cat(Animal):
def eat(self):
print("猫吃鱼")
c = Cat()
c.eat()
抽象方法: 不需要给出具体的方法体, 抽象方法内只写一个pass就行
抽象类: 有抽象方法的类就是抽象类, 抽象类不能创建对象, 抽象类中可以有正常方法
接口: 如果一个类中所有的方法都是抽象方法, 那么这个类就是一个接口
总结: 约束, 就是父类对子类进行约束, 子类必须要重写方法, 在python中约束的方式和方法有两种: (1).使用人为抛出异常的方案, 并且尽量抛出的是NotImplementError, 这样比较专业, 而且错误比较明确(2). 使用抽象类和抽象方法, 由于该方案来源于java和c#, 所以使用频率还是很少的
二. 异常处理 点击了解详情
异常就是程序运行时发生错误的信号(在程序出现错误时, 则会产生一个异常, 若程序没有处理它, 则会抛出该异常, 程序的运行也会终止)
错误分为两种: 语法错误和逻辑错误
异常处理语法:
try:
"""操作"""
except ZeroDivisionError ad e:
"""除数不能为0"""
except FileNotFoundError as e:
"""文件不存在"""
except Exception as e:
"""异常的父类, 可以捕获所有的异常"""
else:
""""保护不抛出异常的代码, 当try中无异常的时候执行"""
finally:
"""最后要执行的操作,总会被执行,收尾操作"""
执行流程: 程序先执行操作, 然后如果走错了会走except中的代码, 如果不出错, 执行else中的代码. 无论如何, 程序最后都会执行finally中的语句
自定义异常: 只要你的类继承了Exception类, 那你的类就是一个异常类,
我们在调试的时候, 最好能看到错误源在哪里, 这是需要引入一个模块traceback, 可以获得我们每个方法的调试信息, 又称为堆栈信息, 这个信息对我们排错是很有帮助的
import traceback
class GenderError(Exception):
pass
class Person:
def __init__(self, name, gender):
self.name = name
self.gender = gender
def nan_zao_tang_xi_zao(person):
if person.gender != "男":
raise GenderExceptionError("性别不对, 这里是男澡堂子")
p1 = Person("alex", "男")
p2 = Person("eggon", "蛋")
# 处理异常
try:
nan_zao_tang_xi_zao(p1)
nan_zao_tang_xi_zao(p2)
except GenderError as e:
val = traceback.format_exc() # 获取到堆栈信息
print(e)
print(val) # 打印堆栈信息
except Exception as e:
print("反正报错了")
四. MD5加密
数据库中的密码要以加密的方式存储
MD5算法是一种不可逆的加密算法, 它是可靠地, 安全的. python中只需要引入hashlib模块就能搞定MD5的加密工作
import hashlib
def my_md5(s):
obj = hashlib.md5(b"fasdffgggqgqeger") # 加盐
obj.update(s.encode("utf-8")) # 加密的必须是字节
miwen = obj.hexdigest()
return miwen
username = input("请输入用户名:")
password = input("请输入密码:")
print(my_md5("alex"))
if username == "wusir" and my_md5(password) == "f9a17839b68095c7e847c3b476a0f9fd" :
print("登陆成功")
else:
print("失败")
五. 日志
为了测试不必现的bug, 我们需要给软件准备一套日志系统, 当出现任何错误的时候, 我们都可以去日志系统查询, python中创建日志系统:
1. 导入logging模块
2. 简单配置一下logging
3. 出现异常的时候(except), 向日志里面写错误信息
具体有两种方式:
1. 一个日志文件
import traceback 点击了解traceback详情
import logging
logging.basicConfig(filename = "x1.txt",
format = "%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s",
datefmt = "%Y-%m-%d %H:%M:%S",
level = 10)
# file.name 文件名
# format 数据的格式化输出, 最终在日志文件中的样子
# 时间 - 名称 - 级别 - 模块: 错误信息
# datefmt 时间的格式
# level 错误的级别权重, 当错误的级别权重大于等于level的时候才会写入文件
# logging.critical("我是critical") # 50
# logging.ERROR("我是error") # 40
# logging.warning("我是警告") # 30
# logging.info("我是基本信息") # 20
# logging.DEBUG("我是调试") # 10
# logging.log(2, "我是自定义")
class JackError(Exception):
pass
for i in range(5):
try:
if i % 3 == 0:
raise FileNotFoundError
elif i % 3 == 1:
raise KeyError
elif i % 3 == 2:
raise JackError
except FileExistsError:
val = traceback.format_exc()
logging.error(val)
except KeyError:
val = traceback.format_exc()
logging.error(val)
except JackError:
val = traceback.format_exc()
logging.error(val)
except Exception:
val = traceback.format_exc()
logging.error(val)
2. 子系统要分开记录日志, 方便调试, 借助文件助手(FileHandler)
import logging
# 创建一个操作日志的对象, logger (依赖于FileHandler)
file_handler = logging.FileHandler("l1.log", "a", encoding = "utf-8")
file_handler.setFormatter(logging.Formatter(fmt = "%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s"))
logger1 = logging.Logger("s1", level = logging.ERROR)
logger1.addHandler(file_handler)
logger1.error("我是A系统")
# 再创建一个操作日志的对象, logger (依赖于FileHandler)
file_handler2 = logging.FileHandler("l2.log", "a", encoding = "utf-8")
file_handler2.setFormatter(logging.Formatter(fmt = "%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s"))
logger2 = logging.Logger("s2", level = logging.ERROR)
logger2.addHandler(file_handler2)
logger2.error("我是B系统")
六、python所有的标准异常类:
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
SystemExit | Python 解释器请求退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |