2019-04-03-day025-异常与日志

时间:2022-12-02 19:20:38

内容回顾

考试

  • 6个小时 120分 (100+20)
  • 15:00-18:00 笔试 60分
  • 19:00-22:00 上机考试 40分 + 20分
  • 60分及格不算附加题
    • 简答题
    • 读程序
    • 简单编程
    • 编程题

异常处理

logging模块

内置方法

class A:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        return self.name

obj = A()
print(obj)
#obj是一个对象,如果我们希望打印的对象是一个人能看的懂
#而不是一串内存地址

__str____repr__

  • 都是在打印对象或者字符串格式化拼接对象的时候自动触发的

__repr__是备胎

__str__的应用场景 :print(obj),format,%s,str(obj),f'{obj}' 优先使用__str__

如果__str__没有实现,那么以上所有场景会自动调用__repr__

__repr__的应用场景 :

%r,repr(obj)会自动调用__repr__方法,如果没有repr,就输出地址
不会找__str__

__new____del__

  • new构造方法
    • 创建一块属于对象的空间
    • new一定是在init之前执行的
    • 单例模式
  • del析构方法
    • 删除一个对象之前
class A:
    def __del__(self):
        print('aaa')
obj = A()
del obj.name # 不会触发析构
del obj.age  # 不会触发析构
# time.sleep(100)
del obj

__call__

  • obj() 会自动触发__call__

with上下文管理

  • __enter__
  • __exit__
  • with 类名( ) as enter返回值:
    • 写我们需要的内容了
  • 写我们需要的内容 之前 执行了enter方法中的内容
  • 写我们需要的内容 之后 执行了exit方法中的内容
  • 上下文管理应用
    • 文件操作
    • 并发编程锁
    • django框架中使用数据库的事务

初识异常和异常处理

两种 异常

  • 一种是语法错误 : 空格 缩进 语法规则
    • 应该在我们写代码的时候就避免
  • 一种是逻辑错误
    • 应该在程序当中写代码处理
      • 条件判断
      • 异常处理

迭代器 StopIteration

pickle EOFError

  • 先认识一下异常
  • 如何去查异常\解决异常
import pickle
def func():
    f = open('test','w')
    pickle.load(f)  # 报错,load一个文件相当于读,w方式是写,所以会报错
def main():
    func()

main()

认识一下 常见的异常

  • name NameError 不定义一个变量就直接使用
    • 1/0 ZeroDivisionError 不能除以一个0
    • l = []
  • l[1] IndexError 超出了索引范围
  • int('aaa') ValueError 强行转换数据的时候给了一个错误的内容
    • d = {}
  • d['key'] KeyError 字典取一个不存在的key
    • class A:pass
  • A.Country AttributeError 访问一个不存在的属性
    • a = 1
  • a() # TypeError 一个不可被调用的内容被调用了
  • import aaa # ModuleNotFoundError 找不到你要调用的模块

异常会导致什么

a = 1
b = 2
print(c)   # 报错,代码就无法继续执行了
print(a+b)

什么是异常处理

  • 是我们在运行程序的过程中,如果遇到错误,就去事先处理它
  • 让我的程序不要因为报错而结束
  • 提高用户体验
  • 提高代码的容错性
try:
    d = {'key':'value'}
    d['name']    # 报错
    print('qqxing')
except KeyError: # 捕获
    pass
print('wahaha')

异常处理

  • 要用到异常处理的标志
  • 有一个结果 是不确定的
    • 从文件里读取
    • 从input接收
    • 爬去各种网页,不存在的网址
l = ['apple','banana','umbrella']
for num,goods in enumerate(l,1):
    print(num,goods)
try:
    choose = int(input('请输入您想选择的商品序号 :'))
    print(l[choose-1])
except ValueError:
    print('请输入一个数字')

多分支

l = ['apple','banana','umbrella']
for num,goods in enumerate(l,1):
    print(num,goods)
try:
    choose = int(input('请输入您想选择的商品序号 :'))
    print(l[choose-1])
except ValueError:
    print('请输入一个数字')
except IndexError:
    print('您输入的序号不在商品列表内')
l = ['apple','banana','umbrella']
for num,goods in enumerate(l,1):
    print(num,goods)
try:
    choose = int(input('请输入您想选择的商品序号 :'))
    print(l[choose-1])
except (ValueError,IndexError):
    print('请输入正确有效的序号')
except NameError:
    print('发生了一个name error')

万能异常 能捕获几乎所有的异常

try:
    a
    [][1]
    {}['key']
    1/0
    import aaa
except Exception:   # 异常的小祖宗
    print('Exception')

查看异常信息

def main():
    a
    [][1]
    {}['key']
    1 / 0
    import aaa

try:
    main()
except Exception as e:   # 异常的小祖宗
    print(e)

try:
    main()
except:   # 异常的小祖宗
    pass

尽量不要用万能异常,如果你用了,一定要写as

多分支和万能异常

l = ['apple','banana','umbrella']
for num,goods in enumerate(l,1):
    print(num,goods)
try:
    choose = int(input('请输入您想选择的商品序号 :'))
    print(l[choose-1])
except (ValueError,IndexError):
    print('请输入正确有效的序号')
except Exception as e:
    print(e)

##Exception万能异常永远放在所有except分支的最后

单分支

try:
    可能发生异常的代码
except 错误类型:
    处理异常

多分支

try:
    可能发生异常的代码
except 错误类型1:
    处理异常
except 错误类型2:
    处理异常
try:
    可能发生异常的代码
except (错误类型1,错误类型2...):
    处理异常

万能异常

try:
    可能发生异常的代码
except Exception as e:
    处理异常,并打印或者记录e

万能异常和多分支

try:
    可能发生异常的代码
except 错误类型1:
    处理异常
except 错误类型2:
    处理异常
except Exception as e:
    处理异常,并打印或者记录e

异常处理之外的其他机制

l = ['apple','banana','umbrella']
for num,goods in enumerate(l,1):
    print(num,goods)

try:
    choose = int(input('请输入您想选择的商品序号 :'))
    print(l[choose-1])
except (ValueError,IndexError) as e1:
    print(e1)
    print('请输入一个正常的序号')
except Exception as e2:
    print(e2)
else:
    print('执行我啦')
  • else: 如果try中的代码顺利的执行完,没有报错,那么就执行else中的代码
  • 是用来汇报整个try中的代码执行成功用的
  • 一般情况下 else中的内容都是安全的 不会有报错隐患

finally语法

l = ['apple','banana','umbrella']
for num,goods in enumerate(l,1):
    print(num,goods)

try:
    choose = int(input('请输入您想选择的商品序号 :'))
    print(l[choose-1])
except (ValueError,IndexError) as e1:
    print(e1)
    print('请输入一个正常的序号')
except Exception as e2:
    print(e2)
finally:
    print('执行我啦')
def func(filename):
    try:
        f = open(filename,'r')
        content = f.read()
        return content
    except Exception as e:
        print(e)
    finally:        # 无论如何都要执行
        f.close()
        print('一定会执行')

ret = func('test')
print(ret)
def wrapper(func):
    def inner(*args,**kwargs):
        try:
            print('before func')
            return func(*args,**kwargs)
        finally:
            print('after func')
    return inner

try:
    f = open('test')
    for line in f:
        a,b = line.strip().split(',')
finally:
    f.close()
    print('执行我啦')

else : 如果try中的代码没有错误就执行
finally : 必须执行
   # 遇到return也先执行finally中的代码
   # 遇到报错也在程序结束之前先执行finally中的代码
try except
try except except
try except ... else
try except ... else finally
try except ... finally
try finally

主动抛异常

raise ValueError

抽象类

父类 子类 如果子类没有实现父类的方法就报错

自定义异常

class Taibai(Exception):
    def __init__(self,msg):
        self.msg = msg
        super().__init__()
    def __str__(self):
        return self.msg

raise Taibai('具体的异常内容')

断言-assert 条件

class Empty(Exception):
    def __init__(self,msg):
        self.msg = msg
        super().__init__()
    def __str__(self):
        return self.msg

class 班级:
    def __init__(self):
        self.students = ['赵大宝']

    def get(self):
        if not self.students:
            raise Empty('学生列表已为空')
        else:
            return self.students.pop()

clas = 班级()
stu1 = clas.get()
print(stu1)
stu2 = clas.get()
print(stu2)

总结

  1. 如何看异常
  2. 如何处理异常
    • try except
    • try except finally
  3. 断言\自定义异常\主动抛异常
  4. assert
  5. 继承Exception
  6. raise

1.异常处理不宜加在大段代码外面

try:
    100行代码
except:
    pass

2.不要写太多个except

try:
    三行代码
except:
    pass

3. 尽量少的使用完成异常,并且一定不要在万能异常内部用pass

4. 在你的程序没有完成之前,不用在程序入口处加异常处理

5. 给代码排错的时候 一定要考虑到已经添加上的异常处理机制

logging模块

  • 日志模块
  • 为什么要写日志
    • 一个卡务系统 : 记录时间 地点 金额
    • 谁在什么时候 删掉了某一个用户
    • 某时某刻登录了系统
    • 检测代码是不是像我们想像的这样执行的
  • 写文件 ,输出到屏幕
    • f.write,print

时间格式,级别控制,更加便捷

*** logging模块不能自动生成你需要的日志

logging模块的使用
   # 简单配置法      ***  编码问题
   # logger对象法   *****

import logging
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S')

logging.debug('debug message')      # 调试
logging.info('info message')        # 普通信息
logging.warning('warning message')  # 警告
logging.error('error message')      # 错误信息
logging.critical('critical message')# 严重错误
  • 默认情况下 不打印warning以下级别的信息
    • 中文显示乱码
    • 不能同时输出到文件和屏幕
  • logger对象的方式来使用logging模块
    • 首先 先创建logger对象
    • 第二 创建一个文件操作符
    • 第三 创建一个屏幕操作符
    • 第四 创建一个格式
  • logger 绑定 文件操作符
  • logger 绑定 屏幕操作符
  • 文件操作符 绑定格式
  • 屏幕操作符 绑定格式
import logging
用logger
#首先 先创建logger对象
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
#第二 创建一个文件操作符
fh = logging.FileHandler('log',encoding='utf-8')

#第三 创建一个屏幕操作符
sh = logging.StreamHandler()

#第四 创建一个格式
fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

#logger 绑定 文件操作符
logger.addHandler(fh)
#logger 绑定 屏幕操作符
logger.addHandler(sh)
#文件操作符 绑定格式
fh.setFormatter(fmt)
#屏幕操作符 绑定格式
sh.setFormatter(fmt)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')