python的异常处理和调试

本文详细介绍了程序中异常处理的方法,包括try...except...else和try...except...finally语句的使用,以及如何通过断言、logging和pdb进行有效的调试。同时,探讨了单元测试的重要性和实施方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常处理

  • 概述:在程序运行过程中,总会遇到到各种各样的错误,有的错误是编程代码有问题造成的,这种错误通常称为BUG,BUG是必须修复的。有的错误时用户输入造成的,这种错误可以通过检查用户的输入来做响应处理。还有一种错误是完全无法再程序运行过中预测的,比如写文件的时候,磁盘满了,写不进去了。在比如从网络中抓取数据,突然断网了,通常这种情况称为异常,在程序中必须要处理的,否则程序会应为各种问题而结束。

  • 遇到错误,最原始的方式解决是事先约定一个错误代码,这样就知道是否有错误,在操作系统提供的调用中非常常用

  • 缺陷:
    1、函数本身返回的数据与错误代码会混在一起,需要大量的判断是否出错
    2、一旦出错,要一级一级上报,直到某个函数可以处理

‘’'try……except……else语句
格式
try:
语句t
except 错误表示码1 as e:
语句1
except 错误表示码2 as e:
语句2
……
except 错误表示码n as e:
语句n
else:
语句e
作用:用来检测“语句t”中的错误,从而让except语句捕获异常并处理
逻辑:
1、如果try后的“语句t”执行时发生异常,就跳回到执行try并执行一个匹配该异常的except子句,异常处理结束,就结束整个try语句(除非处理异常时又引发新的异常)
2、如果try后的“语句t”执行时发生异常,但是却没有匹配的except子句,异常提交到上一级try,或者到程序的最上层
3、如果try后的“语句t”执行时没有发生异常,就不会匹配except子句,如果有else语句,则执行“语句e”,最后结束这个try语句

try……except……else语句

  • 格式
    try:
    语句t
    except 错误表示码1 as e:
    语句1
    except 错误表示码2 as e:
    语句2
    ……
    except 错误表示码n as e:
    语句n
    else:
    语句e
  • 作用:用来检测“语句t”中的错误,从而让except语句捕获异常并处理
  • 逻辑:
    1、如果try后的“语句t”执行时发生异常,就跳回到执行try并执行一个匹配该异常的except子句,异常处理结束,就结束整个try语句(除非处理异常时又引发新的异常)
    2、如果try后的“语句t”执行时发生异常,但是却没有匹配的except子句,异常提交到上一级try,或者到程序的最上层
    3、如果try后的“语句t”执行时没有发生异常,就不会匹配except子句,如果有else语句,则执行“语句e”,最后结束这个try语句

异常处理(try…except…finally语句)

  • 格式
    try:
    语句t
    except 错误表示1 as e:
    语句1
    except 错误表示2 as e:
    语句1
    ……
    except 错误表示n as e:
    语句n
    finally:
    语句f
  • 作用
    作用:无论try语句是否发生异常,都将执行“语句f”

调试

写好的代码能直接运行的概率非常小,总会在不经意间出现各种各样的BUG,有的BUG很简单,看看错误提示就能修改,但是有的BUG很复杂,需要一些调试的手段来发现并解决错误

print调试

print是最简单最原始的调试方式

  • 缺点:将来得删除调试的print,运行结果也会包含一些垃圾信息

断言

  • 使用:凡是用print来辅助调试的地方,都可以换成断言(assert)语句
  • 逻辑:当程序执行到assert语句时,首先计算第一个表达式的值,如果表达式的值为真则继续向下运行,否则断言失败,assert语句会抛出AssertionError异常,异常的信息为第二个表达式的值
  • 缺点:如果将所有的print换成assert也好不到哪里去
  • 优点:在启动程序可以通过命令添加-0参数关闭assert
def func(x):
    assert x != 0, "x is zero"
    return 10 / x
func(0)

logging 调试

  • 使用:把print替换成logging也可以,和assert相比logging不会抛出错误,把错误输入到文件
import logging

#配置输出级别
logging.basicConfig(level=logging.ERROR)
'''
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
'''


def func(x):
    logging.error("x = %d"%(x))
    return 10 / x
func(0)

logging模块详细介绍

pdb自定义开始断点

pdb是一个基于命令行的调试工具,只需要引入内置的pdb模块,并运行set_trace函数就可以触发调试器。通常将这两个操作写在一行中便于将其注释。
命令 简写命令 作用
break b 设置断点
continue c 继续执行程序,直到下一个断点或调用点
list l 查看当前行的代码段
step s 进入函数
return r 执行代码直到从当前函数返回
quit q 中止并退出
next n 执行下一行
print p 打印变量的值
help h 帮助
args a 查看传入参数
回车 重复上一条命令
break b 显示所有断点
break lineno b lineno 在指定行设置断点
break file:lineno b file:lineno 在指定文件的行设置断点
clear num 删除指定断点
bt 查看函数调用栈帧

e = 0
print('----------------------0')
#自定义开始断点
pdb.set_trace()
f = 5
print(1 / e)


# 输出
"""
----------------------0
> e:\python1903\python 基础\day15\code\7、调试(pdb的自定义开始断点).py(11)<module>()
-> f = 5
(Pdb) 
""""

IDE断点调试

断点调试介绍

测试

函数的单元测试

  • 单元测试
    • 作用:用来对一个函数、一个类或者一个模块来进行正确性检测的工具
    • 意义:
      1、假设对函数的代码进行了修改,只需在跑一次单元测试,如果通过,说明此时的修改不会对函数原有的行为造成影响。如果不通过,说明此次的修改与原有行为不一致,要么修改代码,要么修改测试
      2、确保一个程序模块的行为符合设计的测试用例,在将来修改的时候可以极大的保证该模块依然正确
    • 结果:
      1、单元测试通过:说明测试的这个函数或者类能够正常工作
      2、单元测试不通过:要么有BUG,要么测试条件不正确
# calculater模块
def mySum(x, y):
    ret = x + y + 1
    a = 1
    return  ret

def mySub(x, y):
    ret = x - y
    return ret

# main 模块
from calculater import mySum, mySub
if __name__ == "__main__":
    ret1 = mySum(1, 2)
    if ret1 == 3:
        print("ret1 = %d"%ret1)
    #认为正确
    ret2 = mySum(3, 4)
    if ret2 == 8:
        print("ret2 = %d"%ret2)

# test模块
#测试模块
import unittest
from calculater import mySum, mySub

#定义测试类
class Test(unittest.TestCase):
    #测试开始之前调用
    def setUp(self):
        print("开始测试……")

    # 测试结束之后调用
    def tearDown(self):
        print("结束测试……")

    #测试函数名:test__待测试函数名
    #注意:其实也可以不是待测试的函数名
    #本质:只要是以test__开头的函数都会被执行
    def test__mySum(self):
        self.assertEqual(mySum(2, 2), 4)
    def test__mySub(self):
        self.assertEqual(mySub(4, 2), 2)


if __name__ == "__main__":
    unittest.main()

对类进行单元测试

  • myDict模块
class MyDict(dict):
    def __init__(self, *args, **kwargs):
        print("----------1")
        super().__init__(*args, **kwargs)
    def __setattr__(self, key, value):
        print("-----------2")
        self[key] = value
    def __getattr__(self, item):
        try:
            print("--------3")
            return self[item]
        except KeyError as e:
            raise AttributeError("dict not have the key")

    def run(self):
        pass

  • test 模块

import unittest

from myDict import MyDict

#定义测试类
#类名:Test待测试类名
class TestMyDict(unittest.TestCase):
    def setUp(self):
        print("开始测试")
    def tearDown(self):
        print("结束测试")


    # # 实例化阶段
    def test_init(self):
        d = MyDict(a=1, b=2)
        # 断言
        self.assertEqual(d.a, 1)
        self.assertEqual(d.b, 2)
        self.assertTrue(isinstance(d, dict))
    # #
    # # 测试设置属性
    def test__key(self):
        d = MyDict()
        d["key"] = 1
        self.assertTrue("key" in d)
        self.assertEqual(d["key"], 1)
    def test__attr(self):
        d = MyDict()
        d.key = 1
        self.assertTrue("key" in d)
        self.assertEqual(d["key"], 1)


    #判断
    def test__keyerror(self):
        d = MyDict()
        #通过d["key"]访问不存在的属性抛出KeyError异常
        with self.assertRaises(KeyError):
            value = d["key"]
    def tset__attrerror(self):
        d = MyDict()
        # 通过d.key访问不存在的属性抛出AttributeError异常
        with self.assertRaises(AttributeError):
            value = d.key


    #对象函数的测试
    def test__run(self):
        d = MyDict()
        d.run()

if __name__ == "__main__":
    unittest.main()


doctest模块

  • 该模块可以直接提取注释中的代码并执行测试
import doctest

def mySum(x, y):
    # doctest严格按照python交互式命令的输入和输出来判断测试结果是否正确
    '''
    >>> print(mySum(1, 2))
    3
    '''
    return x + y + 1

if mySum(1, 2) == 3:
    print("bingle is a good man")



if mySum(1, 1) == 3:
    print("bingle is a nice man")


# 提取注释中代码执行
doctest.testmod()



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值