Python程序异常处理:try、except、else、finally

输入与预期不匹配,触发异常,程序退出:
在这里插入图片描述

一、异常处理:使用try、except进行错误处理

为了保证程序运行的稳定性,错误应该被程序捕捉并合理控制

  • Python使用保留字try和except进行异常处理。
    在这里插入图片描述
  • 语句块1是正常执行的程序内容,当执行这个语句块发生异常时,即执行except后面的语句块2
try:
    n = eval(input("请输入一个数字:"))
    print("输入数字的3次方值为:", n ** 3)
except:
    print("输入错误,请输入一个数字!")

请输入一个数字:abc
输入错误,请输入一个数字!

二、异常处理:使用try、except处理程序运行错误

以下语句发生除零的情况,程序报错:
在这里插入图片描述
捕捉错误:

try:
    for i in range(4):
        print(10 / i, end="")
except:
    print("某种原因,出错了!")
某种原因,出错了!

三、异常处理:使用try、except处理特定的错误类型

在except后指明错误类型

try:
    for i in range(5):
        print(10/i, end="")
except ZeroDivisionError:
    print("除数为零,产生了除零错误!")
except:
    print("某种原因,出错了!")

编写程序中,建议在输入合规性判断、保证关键代码可靠性等方面广泛使用异常处理机制。

四、try、except高级用法

在这里插入图片描述

  1. 执行逻辑:Python先执行语句块1,如果语句块1不发生异常则奖励性地执行else语句块3;如果发生了异常则执行except语句块2;无论发不发生异常,最后都要执行finally语句块4.
  2. 一个这样写的理由是:如果finally里有一个语句可能会发生异常,你可以把这个可能的异常放在外层,在外层来处理掉它,让finally语句顺利final。用来测试程序是不是考虑周全可以final了。
  3. 反对这种写法的一个理由是:在很多情况下,异常处理器需要做一些扫尾工作。
  4. 一个最终的注意点:如果 finally 中的代码引发了另一个异常或由于 return,break,continue 语法而终止,原来的异常将丢失而且无法重新触发。

五、case:猜数字游戏

版本1:

import random
target = random.randint(1, 10)
count = 0
while True:
    guess = eval(input("请输入一个整数:"))
    count += 1
    if guess > target:
        print("猜大了")
    elif guess < target:
        print("猜小了")
    else:
        print("猜对了")
        break
print("此轮的猜测次数是:", count)

如果用户输入非数字,会产生运行错误,接着程序退出。为了增加程序鲁棒性,需要增加异常处理机制。

版本2:

import random
target = random.randint(1, 10)
count = 0
while True:
    try:
        guess = eval(input("请输入一个猜测的整数:"))
    except:
        print("输入有误,请重试,不计入猜测次数哦")
        continue
    count += 1
    if guess > target:
        print("猜大了")
    elif guess < target:
        print("猜小了")
    else:
        print("猜对了")
        break
print("此轮的猜测次数是:", count)

六、二分查找法

  • 数学上有一个经典的搜索算法:二分查找法,即每次都猜(最大值+最小值)/2的那个值,根据反馈的大小情况继续查找,直到找到结果。通过二分查找法,每次获得的搜索范围都比前一次缩小一半。
  • 如,初次为1到N的整数范围,采用二分查找法需要logN(以2为基数)次即可找到结果。当N为1000时,logN的值为10,即最多不超过10次。
import math
a = math.log(1000, 2)
print(a)

9.965784284662087

版本2的测试:

请输入一个猜测的整数:500
猜小了
请输入一个猜测的整数:750
猜小了
请输入一个猜测的整数:875
猜大了
请输入一个猜测的整数:812.5
猜大了
请输入一个猜测的整数:781.25
猜小了
请输入一个猜测的整数:796.87
猜大了
请输入一个猜测的整数:789.06
猜小了
请输入一个猜测的整数:793
猜大了
请输入一个猜测的整数:791
猜小了
请输入一个猜测的整数:792
猜对了
此轮的猜测次数是: 10

七、小结

一个正常运行的case:

def example(x, y):
    return x[y]
x = "abc"
print(example(x, 2))

输出:
c

修改后,运行报错退出运行:

Traceback (most recent call last):
  File "C:/Users/520/PycharmProjects/pythonProject1/exercise.py", line 4, in <module>
    print(example(x, 4))
  File "C:/Users/520/PycharmProjects/pythonProject1/exercise.py", line 2, in example
    return x[y]
IndexError: string index out of range

第一: try不仅捕获异常,而且会恢复执行

def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 4))
    except:
        print("got exception")
    print("程序出错,请修改")

test()

输出:
got exception
程序出错,请修改

第二:无论try是否发生异常,finally是无论是否捕捉到异常都会被执行,finally 可以单独和try搭配,也可以和except,包括else一起配合使用。

def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 4))
    except:
        print("got exception")
    finally:
        print("这是finally语句块")
    print("程序出错,请修改")

test()

输出:
got exception
这是finally语句块
程序出错,请修改

第三:try无异常,才会执行else

def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 4))
    except:
        print("got exception")
    else:
        print("这是else语句块")
    finally:
        print("这是finally语句块")
    print("程序出错,请修改")

test() #程序异常,不会执行else语句块

输出:
got exception
这是finally语句块
程序出错,请修改
def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 2))
    except:
        print("got exception")
    else:
        print("这是else语句块")
    finally:
        print("这是finally语句块")
    print("程序出错,请修改")

test() #程序正常,输出else语句块

输出:
c
这是else语句块
这是finally语句块
程序出错,请修改

else作用:没有else语句,当执行完try语句后,无法知道是没有发生异常,还是发生了异常并被处理过了。通过else可以清楚的区分开。

第四:利用raise传递异常

  • raise语句不包括异常名称或额外资料时,会重新引发当前异常。如果希望捕获处理异常,又不希望异常在程序代码中消失,可以通过raise重新引发该异常。
def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 4))
    except:
        print("got exception")
        raise
    else:
        print("这是else语句块")
    finally:
        print("这是finally语句块")
    print("程序出错,请修改")

test()

输出:
Traceback (most recent call last):
  File "C:/Users/520/PycharmProjects/pythonProject1/exercise.py", line 17, in <module>
    test()
  File "C:/Users/520/PycharmProjects/pythonProject1/exercise.py", line 7, in test
    print(example(x, 4))
  File "C:/Users/520/PycharmProjects/pythonProject1/exercise.py", line 2, in example
    return x[y]
IndexError: string index out of range   #正常执行语句同时可以捕获异常
got exception  
这是finally语句块

第五:指定异常具体类型except(name1, name2)

  • 如果except后无任何参数,则捕获所有异常;except后有参数,捕获参数列出的异常。
def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 4))
    except IndexError:  #指定只有IndexError才会执行except语句
        print("got exception")
    else:
        print("这是else语句块")
    finally:
        print("这是finally语句块")
    print("程序出错,请修改")

test()

输出:
got exception
这是finally语句块
程序出错,请修改
def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 4))
    except (TypeError, IndexError):  #指定两个异常类型
        print("got exception")
    else:
        print("这是else语句块")
    finally:
        print("这是finally语句块")
    print("程序出错,请修改")

test()

输出:
got exception
这是finally语句块
程序出错,请修改

在这里插入图片描述
第六、注意:不建议在finally语句块中使用return语句

def example(x, y):
    return x[y]

x = "abc"
def test():
    try:
        print(example(x, 4))
    except :
        print("got exception")
        print(1 / 0)  #因为finally里的return,except里的这个异常不会打印出来
    finally:
        print("这是finally语句块")
        return 10
    print("程序出错,请修改")  #因为finally里的return,这个print不会打印出来

test()

输出:
got exception
这是finally语句块
  • 当finally中有return时,try/except虽然有异常但是并没有抛出,这是因为在try/except/else/finally逻辑中,finally执行逻辑比try/except异常抛出执行的逻辑要优先,注意是finally执行逻辑比try/except中异常抛出的优先级要高,而不是try/except中非异常代码逻辑的优先级
  • 这也可以从官方文档得到体现:
    A finally clause is always executed before leaving the try statement, whether an exception has occurred or not. When an exception has occurred in the try clause and has not been handled by an except clause (or it has occurred in a except or else clause), it is re-raised after the finally clause has been executed. The finally clause is also executed “on the way out” when any other clause of the try statement is left via a break, continue or return statement.
    大致意思就是:就是说except、else子句中的异常在finally子句执行之后才会抛出,但是finally直接return了,所以我们就看不到异常了,而且会覆盖本身的return值。这种用法显然是不符合初衷的,所以不建议在finally语句中使用return、break、continue这些跳出的语句,应仅用作资源释放操作,否则会出现意想不到的结果。

PS: for reference, python123.io

猜你喜欢

转载自blog.csdn.net/weixin_47008635/article/details/113787216