python raise语句_Python知识精解:Python异常及解决办法

异常是什么

Python 异常是指在程序运行中所产生的错误,即代码在无法正常执行的情况下就会产生异常。这个错误可以是Python内置的错误类型,也可以是开发者自定义的错误类型。异常即一个事件,异常会影响程序的执行流程,若没有用正确的方式捕获产生的异常,代码就会终止运行。

产生异常的情况举例

举一些Python常见的发生异常的场景:

比如将一个字母转换为整型。这时Python会自动抛出TypeError异常。

>>> int("python")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'python'

在比如从字典中取一个不存在的键,Python会自动抛出KeyError异常。

>>> dict_demo = {}
>>> key_demo = dict_demo["fun"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'fun'

这里出现的TypeError和KeyError都是Python内置的异常类型,它们都继承自父类Exception。

情况还有很多,这里不一一举例了。

自定义异常

Python允许定义自定义的错误类型。下面来定义一个自定义异常DemoError:

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message

抛出异常

使用raise可以抛出异常。

# 抛出异常:
raise Exception("This is a Exception.")
 
# 抛出指定异常,可以是Python内置的异常类型,也可以是自定义的异常类型
# 抛出内置异常
raise TypeError("This is a TypeError.")
 
# 抛出自定义的异常
raise DemoError("This is my Exception ---- DemoError.")

在Python执行过程中,遇到raise抛出异常时,会跳出当前语句块,寻找捕获该异常的语句。如果代码中没有对抛出的异常进行捕获,程序就会报错。

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    print("I will raise a Exception in this process.")
 
    raise DemoError("Just a test.")
 
    print("After raise Exception...")

上面的代码中运行抛出DemoError,运行结果如下:

I will raise a Exception in this process.
Traceback (most recent call last):
  File "/Users/my/Desktop/Python Apps/untitled_test/test4.py", line 12, in <module>
    raise DemoError("Just a test.")
__main__.DemoError: DemoError: Just a test.

可以看到raise下面的语句没有打印。因为代码中没有捕获抛出的异常,所以程序执行到12行报错。

对于Python内置的异常,通常会在使用不正确的Python语法时会自动抛出。例如运行Python脚本中包含错误的Python语法时会抛出SyntaxError。

>>> a = 5
>>> if a < 3
  File "<stdin>", line 1
    if a < 3
           ^
SyntaxError: invalid syntax

我们也可以自己主动抛出内置的异常类型,并加上自己想要的错误描述:

>>> raise SyntaxError("Nothing...")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SyntaxError: Nothing...

下面的一节内容会告诉大家怎么捕获异常(即异常怎么处理)。

异常处理

1. 捕获异常

在Python中使用try-except来捕获异常。

except用来捕获try块中抛出的异常。

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise DemoError("Just a test.")
 
        print("After raise Exception...")
    except:
        print("In except..")

except捕获任何异常类型。当异常被捕获时,代码的执行就会进入except块中。上面代码的执行情况如下:

I will raise a Exception in this process.
In except..

使用except Exception与上面的捕获类似,功能依旧是捕获任何异常类型。不过可以对异常对象做出一些处理,比如打印出异常中包含的信息:

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise DemoError("Just a test.")
    except Exception as e:
        print("In except..")
        print(str(e))

代码的执行结果如下:

I will raise a Exception in this process.
In except..
DemoError: Just a test.

注意输出的最后一行,print(str(e))将异常中包含的错误信息打印了出来。

但是,使用类似except Exception这样的语句捕获任何异常也会有一些问题:

这样处理异常的方式有些泛化,类似于直接输出发生了一个错误。大多数情况下,代码还是要对捕获到的不同异常做出不同的应对。

使用 except 异常类型名称可以捕获特定类型的异常。

例如下面的代码:

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise DemoError("Just a test.")
    except DemoError as e:
        print("It's a DemoError!")
        print(str(e))

上面的代码中仅仅捕获了DemoError,执行结果如下:

I will raise a Exception in this process.
It's a DemoError!
DemoError: Just a test.

如果我将上面的代码换成其他异常,比如KeyError:

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise KeyError("Just a test.")
    except DemoError as e:
        print("It's a DemoError!")
        print(str(e))

代码执行就会报错:

Traceback (most recent call last):
  File "/Users/my/Desktop/Python Apps/untitled_test/test4.py", line 13, in <module>
    raise KeyError("Just a test.")
KeyError: 'Just a test.'
I will raise a Exception in this process.

因为代码中没有对KeyError捕获的代码块,因此也就无法处理这种异常。

现在我们来修复这个bug:

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise KeyError("Just a test.")
    except DemoError as e:
        print("It's a DemoError!")
        print(str(e))
    except KeyError as e:
        print("Oh, It's a KeyError.")

再次执行程序,会看到KeyError被捕获:

I will raise a Exception in this process.
Oh, It's a KeyError.

在Python中,try-except不一定是要成对出现的。一个try块后可以有多个except块,就像上面看到的例子那样。

但是如果except捕获异常时有冲突怎么办?来看看下面的代码:

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise KeyError("Just a test.")
    except Exception as e:
        print("I can not get your error type.")
    except DemoError as e:
        print("It's a DemoError!")
        print(str(e))
    except KeyError as e:
        print("Oh, It's a KeyError.")

13行抛出了KeyError异常,而14行的 except Exception as e可以捕获任何异常类型。那么代码到底是执行14行的except代码块,还是执行19行针对KeyError捕获的except代码块呢?

看一下执行结果:

I will raise a Exception in this process.
I can not get your error type.

看来程序进入14行的代码块,并没有进入19行的except KeyError。

出现这种现象是因为except是顺序匹配异常的。如果匹配到可以捕获的异常,就进入该except块中。

还是刚刚的代码,稍稍调整下except块的顺序:

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise KeyError("Just a test.")
    except DemoError as e:
        print("It's a DemoError!")
        print(str(e))
    except KeyError as e:
        print("Oh, It's a KeyError.")
    except Exception as e:
        print("I can not get your error type.")

这时我们执行代码:

I will raise a Exception in this process.
Oh, It's a KeyError.

可以看到代码流程进入了except KeyError语句块中。

?在try-except的最后一个except块中可以加一个except Exception的语句块,用来捕获开发过程中意料之外的异常,不至于使程序崩溃。

2. finally语句

上面所说的try-except语句用于捕获异常。还有一种不太常见,且稍稍复杂的语句结构:try-except-finally。与之前的类似,异常在except中捕获,但是在except块执行完毕后,代码会接着在finally中继续执行。

class DemoError(Exception):
    def __init__(self, message):
        self.message = "DemoError: " + message
 
    def __str__(self):
        return self.message
 
 
if __name__ == "__main__":
    try:
        print("I will raise a Exception in this process.")
 
        raise KeyError("Just a test.")
    except DemoError as e:
        print("It's a DemoError!")
        print(str(e))
    except KeyError as e:
        print("Oh, It's a KeyError.")
    except Exception as e:
        print("I can not get your error type.")
    finally:
        print("In the finally...")

程序运行的结果如下:

I will raise a Exception in this process.
Oh, It's a KeyError.
In the finally...
?提示:finally语句是可选的,可以根据实际情况决定是否需要添加finally语句块

如果在except中使用return语句,那么还会执行finally语句块吗?

先来看看下面的代码:

def fun():
    try:
        print("I will raise a Exception in this process.")
 
        raise KeyError("Just a test.")
    except KeyError as e:
        print("Oh, It's a KeyError.")
        return
    finally:
        print("In the finally...")
 
 
if __name__ == "__main__":
    fun()

注意在第8行,也就是finally语句之前,使用了return语句。程序的执行结果如下:

I will raise a Exception in this process.
Oh, It's a KeyError.
In the finally...

可以看出,尽管在except语句块中使用了return语句,但Python仍然会执行finally语句块。

Python在except中使用return会继续处理finally中的代码。

那么,,如果想强行在except中结束,而不处理finally中的代码呢?

恐怕只有删掉finally语句块了。(就算在except语句块中强行增加exit()也是不行的,Python依然会执行finally块)

觉得有用的同学可以点下赞同呀~

关注我,获得更多技术知识~

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值