Python——异常处理机制

Python 异常处理机制

Python异常与异常处理机制

Python使用称为异常的特殊对象来管理程序执行期间发生的错误(Python中一切皆对象,包括异常也是对象)。每当发生程序错误,都会创建一个异常对象。如果编写了处理该异常的代码,程序将继续运行;但是如果未编写代码对异常进行处理,程序将停止并显示traceback,其中包含有关异常的报告

异常处理是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况,即超出程序正常执行流程的某些特殊条件。异常处理机制是使用 try-except 代码块处理异常,try-except 代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。使用try-except 代码块时,即便出现异常,程序也将继续运行,同时显示你编写的友好的错误消息,而不是令用户迷惑的traceback

Python提供了两个非常重要的功能来处理程序在运行中出现的异常和错误。经常使用的是try...except语句,拓展一下就是try-except-else-finally,另一个是断言,即assert

针对 Traceback 的解读

Traceback 是 Python 错误信息的报告,当你的程序导致异常时,Python 将打印 Traceback 以帮助你知道哪里出错了。虽然 Python 的 Traceback 提示信息看着挺复杂,但是里面存在丰富的信息,可以帮助你诊断和修复代码中引发异常的原因,以及定位到具体哪个文件的哪行代码出现的错误,这样有助于我们编写对应的异常处理代码来捕获异常,并给出合适的错误提示信息。所以说学会看懂 Traceback 信息是非常重要的

下面给出一个案例进行分析,这是一种导致Python引发异常的简单错误:除0

python 复制代码
# calculate.py文件的内容
def divide(a, b):	# 进行除法运算的函数
    return a / b

# main.py文件的内容
from calculate import divide

divide(5, 0)

# 抛出异常:
"""
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 3, in <module>
    divide(5, 0)
  File "C:\编程\Python代码\test\calculate.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero
"""
  • 错误输出的最后一行一般会告诉你引发了什么类型的异常,以及关于该异常的一些相关信息,所以看错误信息的最后一行就能获知到错误的原因
    • 在上述 traceback 中,最后一行指出的错误 ZeroDivisionError 就是一个异常对象,并且给出了具体的描述 division by zero,即表示因为除0,导致程序抛出该异常
  • 错误输出的前面几行的阅读顺序应该是由下而上的,因为越往上,离抛出异常的实际位置越远,越难定位到抛出异常的代码
  • 这一部分要每连续两行为一组进行阅读。其中每组的第1行会告诉你是在哪个文件的、哪个函数的、哪一行出错了,也就是会更直接的告诉你错误发生的位置;每组的第2行会把报错的那一行代码显示出来
  • 比如在程序里A函数调用了B函数,然后B函数调用了C函数,而C函数报错了,那么 traceback 中的前几行从下至上的顺序来看,会先显示C函数的信息,再显示B函数的信息,再显示A函数的信息,而且每一个函数的信息都是按两行来组织的,其中第1行展示位置,第2行展示代码
    • 在上述 traceback 中,前面几行中的最后一行定位的位置为位于 calculate.py 文件中的第2行,并且位于 divide 函数代码块中,具体抛出异常的代码为"return a / b"
    • 然后我们看上一行,定位的位置为位于 main.py 文件中的第3行,并且位于引入模块的代码中,具体抛出异常的代码为"divide(5, 0)"
  • 最上面第一行的内容是固定不变的,始终Traceback (most recent call last)",可以忽略

try-except-else-finally

  • try:正常情况下,程序计划执行的语句
  • except:程序异常时执行的语句
  • else:程序无异常即try段代码正常执行后会执行该语句
    • 当try语句的相关代码中的return,continue或break语句被执行时,else语句将被忽略
  • finally:不管有没有异常,都会执行的语句
    • 具体来说,当try,except或else语句的相关代码中存在某些跳转语句时,比如break,continue和return,与finally语句相关的代码将在这些跳转语句执行之前被执行
    • 在处理 Python 异常的过程中,一些代码需要始终被执行,无论是否有 Python 异常被抛出,或 Python 异常是否被处理。使用finally语句可以达成上述目标,该语句之后的代码通常与清理工作有关,比如,关闭打开的文件

运行逻辑1:首先运行try中的代码块,当出现异常时,终止try中代码块的执行,立即执行except中的代码块,最后执行finally中的代码块

python 复制代码
try:
    print('输出:我是try1')
    a = 5 / 0
    print('输出:我是try2')

except :
    print('输出:我是except')

else :
    print('输出:我是else')

finally :
    print('输出:我是finally')

# 输出结果:
"""
输出:我是try1
输出:我是except
输出:我是finally
"""

运行逻辑2:首先运行try中的代码块,当执行完毕后,代码始终没有抛出异常,继续执行else中的代码块,最后执行finally中的代码块

python 复制代码
try:
    print('输出:我是try1')
    a = 5 / 1
    print('输出:我是try2')

except :
    print('输出:我是except')

else :
    print('输出:我是else')

finally :
    print('输出:我是finally')

# 输出结果:
"""
输出:我是try1
输出:我是try2
输出:我是else
输出:我是finally
"""

运行逻辑3:函数中,如果finally语句的相关代码中包含了return语句,那么该return语句所返回的值(包括空值None),将取代try,except或else语句相关代码中的返回值

因为finally中的代码块在设定上必须执行:

  • 在try中的代码块return之前,会执行finally中的语句,try中的return被忽略了,最终返回的值是finally中return值
  • try中的代码块没有return语句,执行完毕后,会继续执行else中的语句,在else中的代码块return之前,执行finally中的语句,else中的return被忽略了,最终返回的值是finally中return值
  • try中的代码块中抛出异常,被except捕获,在except中的代码块return之前,执行finally中的语句,except中的return被忽略了,最终返回的值是finally中return值
python 复制代码
def test():
    try:
        print('输出:我是try1')
        a = 5 / 0
        print('输出:我是try2')
        return 1

    except :
        print('输出:我是except1')
        return 2
        print('输出:我是except2')

    else :
        print('输出:我是else')
        return 3

    finally :
        print('输出:finally')
        return 4

num = test()
print(num)

# 输出结果:
"""
输出:我是try1
输出:我是except1
输出:finally
4
"""


def test():
    try:
        print('输出:我是try1')
        a = 5 / 1
        print('输出:我是try2')
        return 1

    except :
        print('输出:我是except')
        return 2

    else :
        print('输出:我是else')
        return 3

    finally :
        print('输出:finally')
        return 4

num = test()
print(num)

# 输出结果:
"""
输出:我是try1
输出:我是try2
输出:finally
4
"""


def test():
    try:
        print('输出:我是try1')
        a = 5 / 1
        print('输出:我是try2')
        # return 1

    except :
        print('输出:我是except')
        return 2

    else :
        print('输出:我是else1')
        return 3
        print('输出:我是else2')

    finally :
        print('输出:finally')
        return 4

num = test()
print(num)

# 输出结果:
"""
输出:我是try1
输出:我是try2
输出:我是else1
输出:finally
4
"""

运行逻辑4:函数中,finally中不存在return,并且try中代码块没有抛出异常,那么按照 运行逻辑2,函数返回的是try或者else代码中先出现的那个return值

因为代码中程序正常运行,不一定要执行else中的代码块,如果try中return直接结束函数执行了,那么就不会执行else中的代码块

python 复制代码
def test():
    try:
        print('输出:我是try1')
        a = 5 / 1
        print('输出:我是try2')
        return 1

    except :
        print('输出:我是except')
        return 2

    else :
        print('输出:我是else')
        return 3

    finally :   # finally中不存在return语句
        print('输出:finally')
        # return 4  

num = test()
print(num)

# 输出结果:
"""
输出:我是try1
输出:我是try2
输出:finally
1
"""


def test():
    try:
        print('输出:我是try1')
        a = 5 / 1
        print('输出:我是try2')
        # return 1

    except :
        print('输出:我是except')
        return 2

    else :
        print('输出:我是else')
        return 3

    finally :   # finally中不存在return语句
        print('输出:finally')
        # return 4  

num = test()
print(num)

# 输出结果:
"""
输出:我是try1
输出:我是try2
输出:我是else
输出:finally
3
"""

运行逻辑5:函数中,finally中不存在return,并且try中代码块产生异常,那么按照 运行逻辑1,函数返回的是except代码中的那个return值

因为代码中程序抛出异常,必须执行except中的代码块

python 复制代码
def test():
    try:
        print('输出:我是try1')
        a = 5 / 0
        print('输出:我是try2')
        return 1

    except :
        print('输出:我是except')
        return 2

    else :
        print('输出:我是else')
        return 3

    finally :   # finally中不存在return语句
        print('输出:finally')
        # return 4  

num = test()
print(num)

# 输出结果:
"""
输出:我是try1
输出:我是except
输出:finally
2
"""

except语句

except语句的机制

每一个try语句,都必须至少有一个except语句,除非存在 finally 语句

  • 一般一个try语句后面都需要存在至少一个except语句,但是使用 finally 语句后 except 语句将成为可选的,try语句之后可以没有任何except语句
python 复制代码
try:
	print("No Error")
	
# 抛出异常:SyntaxError: unexpected EOF while parsing

try:
	5/0
	
# 抛出异常:SyntaxError: unexpected EOF while parsing


try:
	print("No Error")

finally:
	print("Something must be done")

# 输出结果:
"""
No Error
Something must be done
"""


try:
	5/0

finally:
	print("Something must be done")

# 输出结果:
"""
Something must be done
Traceback (most recent call last):
  File "C:\编程\Python代码\test\test.py", line 3, in <module>
    5/0
ZeroDivisionError: division by zero
"""

使用 else 语句的前提是至少拥有一个 except 语句

  • 如果要使用else语句来处理没有 Python 异常被引发的情况,那么在try语句之后,必须至少存在一个except语句
python 复制代码
try:
	print("No Error")

else:
	print("must have except")

finally:
	print("Something must be done")

# 抛出异常:SyntaxError: invalid syntax


try:
	print("No Error")

except:
	print("waiting for error")

else:
	print("must have except")

finally:
	print("Something must be done")

# 输出结果:
"""
No Error
must have except
Something must be done
"""

一个try...except语句中可以拥有多个except语句,都是最多只有一个 except 语句能与被抛出 Python 异常匹配

  • 如果try...except语句拥有多个except语句,那么与 Python 的 if 语句类似,他们会按照先后顺序进行匹配,当某一个except语句与被抛出的 Python 异常匹配时,其余的except语句将被忽略
python 复制代码
try:
	5/0

except IndexError as e:			# 无法捕获除0异常
	print("IndexError")

except ZeroDivisionError as e:	# 可以捕获除0异常
	print("ZeroDivisionError1")

except ZeroDivisionError as e:	# 可以捕获除0异常
	print("ZeroDivisionError2")

except BaseException as e:		# 可以捕获除0异常
	print("BaseException")

# 输出结果:ZeroDivisionError1


try:
	5/0

except IndexError as e:			# 无法捕获除0异常
	print("IndexError")

except BaseException as e:		# 可以捕获除0异常
	print("BaseException")

except ZeroDivisionError as e:	# 可以捕获除0异常
	print("ZeroDivisionError1")

except ZeroDivisionError as e:	# 可以捕获除0异常
	print("ZeroDivisionError2")

# 输出结果:BaseException

except可以处理一个专门的异常,也可以处理包含在元组中的一组异常

  • 可以将多个异常类型放在一个括号中,通过逗号分隔。当try块引发其中任何一个异常时,程序都将跳转到该except块,处理这个异常
python 复制代码
try:
	5 / 0

except (IndexError, ZeroDivisionError) as e:	# 可以捕获除0异常
	print("IndexError or ZeroDivisionError")

except BaseException as e:		# 可以捕获除0异常
	print("ZeroDivisionError1")

# 输出结果:IndexError or ZeroDivisionError

如果except后没有指定异常类型,则默认捕获所有的异常

  • 此时捕获异常范围为BaseException(后面会提到)
  • 这样的没有指定异常类型的 except 语句要求必须是最后一个 except 语句,否则程序报错
  • 原因很简单,如果它位于其他except语句之前,那么一些except语句将失去被执行的可能
python 复制代码
try:
	5 / 0

except:	# 可以捕获所有异常
	print("捕获到异常")

# 输出结果:捕获到异常

与所有 except 语句均不匹配的 Python 异常将被重新抛出

  • 如果一个 Python 异常被引发,并且与所有的except语句均不匹配,那么该异常将作为未处理的 Python 异常被重新抛出,这可能导致整个程序因此结束执行(当然,finally中的代码块依旧会被执行)
python 复制代码
try:
	5/0

except IndexError as e:		# 无法捕获除0异常
	print("IndexError")

except KeyError as e:		# 无法捕获除0异常
	print("KeyError")

except ValueError as e:		# 无法捕获除0异常
	print("ValueError")

finally:
	print('输出:finally')

# 抛出异常:
"""
输出:finally
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 2, in <module>
    5/0
ZeroDivisionError: division by zero
"""
在 except 语句中引用当前被处理的 Python 异常

在except语句中,使用as关键字可以指定一个与被处理异常绑定(指向异常对象)的标识符(可将其简单的视为 Python 变量),即可通过该标识符在except语句相关的代码中访问被处理的 Python 异常

此外,在 3.11 或更高版本中,通过sys模块的exception函数,同样可在except语句相关的代码中访问当前被处理的 Python 异常

  • 异常对象的常用属性
    • args:包含有关异常的错误编号和异常的描述的元组
    • strerror:异常的描述
    • errno:与异常的错误编号
python 复制代码
try:
	open("no_exit_file.txt", "r")

except FileNotFoundError as e:	# 可以捕获除0异常
    print("异常对象:", e)
    print("异常类型:", type(e))

    # 异常对象的常用属性
    print("异常信息: ", e.args)      # 该属性返回异常的错误编号和描述
    print("异常描述: ", e.strerror)  # 该属性返回异常的描述
    print("错误号: ", e.errno)       # 该属性返回异常的错误编号

# 输出结果:
"""
异常对象: [Errno 2] No such file or directory: 'no_exit_file.txt'
异常类型: <class 'FileNotFoundError'>
异常信息:  (2, 'No such file or directory')
异常描述:  No such file or directory
错误号:  2
"""

except 语句会删除使用 as 关键字与 Python 异常绑定的标识符

  • 如果在某个except语句中使用了as关键字,那么as关键字指定的标识符,将在该except语句的相关代码执行完毕时被删除。这意味着标识符仅在except语句中保持其正确性,他不应该与同一命名空间的其他标识符重复,以避免一些不必要的错误
python 复制代码
try:
	open("no_exit_file.txt", "r")

except FileNotFoundError as e:	# 可以捕获除0异常
    print("异常对象:", e)
    print("异常类型:", type(e))

print(e)

# 输出结果:
"""
异常对象: [Errno 2] No such file or directory: 'no_exit_file.txt'
异常类型: <class 'FileNotFoundError'>
Traceback (most recent call last):
  File "C:\编程\Python代码\test\test.py", line 9, in <module>
    print(e)
NameError: name 'e' is not defined
"""

finally语句

finally语句执行后才能抛出未被处理的异常

当try,except或else语句的相关代码引发不能被处理的 Python 异常时,这些异常不会被立即抛出,他们需要等待finally语句的相关代码的执行

python 复制代码
try:
	5/0

except IndexError as e:		# 无法捕获除0异常
	print("IndexError")

except KeyError as e:		# 无法捕获除0异常
	print("KeyError")

except ValueError as e:		# 无法捕获除0异常
	print("ValueError")

finally:
	print('输出:finally')

# 抛出异常:
"""
输出:finally
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 2, in <module>
    5/0
ZeroDivisionError: division by zero
"""


try:
    5 / 0

except ZeroDivisionError as e:
    print("ZeroDivisionError异常被捕获")
    raise e

finally:
    print('输出:finally')
# 输出结果:
"""
ZeroDivisionError异常被捕获
输出:finally
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 6, in <module>
    raise e
  File "C:\编程\Python代码\test\main.py", line 2, in <module>
    5 / 0
ZeroDivisionError: division by zero
"""


try:
    5 / 1

except ZeroDivisionError as e:
    print("ZeroDivisionError异常被捕获")

else:
    print('输出:else')
    raise ZeroDivisionError("重新抛出的ZeroDivisionError")

finally:
    print('输出:finally')
# 输出结果:
"""
输出:else
输出:finally
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 9, in <module>
    raise ZeroDivisionError("重新抛出的ZeroDivisionError")
ZeroDivisionError: 重新抛出的ZeroDivisionError
"""
finally中执行return会导致异常丢失

如果finally语句的相关代码中包含了跳转语句,比如break,continue或return,那么这些跳转语句的执行,将导致未被except处理的 Python 异常不再被重新抛出,即便这些异常是通过raise语句主动抛出的

3.8 版本之前,在 Python 的finally语句的相关代码中,不能使用continue语句

finally中出现return语句,如果try中抛出的异常没有被捕获到,按理说当finally执行完毕后,应该被再次抛出,但finally里执行了return,导致异常被丢失,所以实际应用中,不推荐在finally中使用return返回

python 复制代码
def test():
	try:
		5/0
		print("函数中的后续代码被执行")

	except IndexError as e:		# 无法捕获除0异常
		print("IndexError")

	except KeyError as e:		# 无法捕获除0异常
		print("KeyError")

	except ValueError as e:		# 无法捕获除0异常
		print("ValueError")

	finally:
		print('输出:finally')
		return 1

num = test()
print(num)

print("后续代码被执行")

# 输出结果:
"""
输出:finally
1
后续代码被执行
"""

raise 语句

raise 语句以及异常对象

使用 Python 提供的raise语句,开发人员可以主动抛出(引发)一个 Python 异常

python 复制代码
raise 语句基本的语法形式为 raise <exception>
  • exception
    • 被抛出的 Python 异常对象,或 Python 异常类型如果仅给出异常类型,那么将根据该类型隐式创建其对应的实例,比如,raise ZeroDivisionError的效果等同于raise ZeroDivisionError()
python 复制代码
raise ZeroDivisionError

# 抛出异常:
"""
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 1, in <module>
    raise ZeroDivisionError
ZeroDivisionError
"""

# 前后对比,发现效果一致
raise ZeroDivisionError()

# 抛出异常:
"""
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 1, in <module>
    raise ZeroDivisionError()
ZeroDivisionError
"""

创建异常对象时可以指定其魔法方法__str__的返回值

python 复制代码
# 判断ZeroDivisionError()返回的东西是否为ZeroDivisionError的实例对象
ins = ZeroDivisionError()
flag = isinstance(ins, ZeroDivisionError)	
print(flag)

# 输出结果:True

ins = ZeroDivisionError()
dir(ins)	# 可以获知,该实例对象具有魔法方法__str__

# 输出结果:
"""
['__cause__', '__class__', '__context__', '__delattr__', '__dict__', '__dir__', 
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',
 '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', 
 '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', 
 '__subclasshook__', '__suppress_context__', '__traceback__', 'args', 'with_traceback']
"""

# 由于调用print函数实际是执行实例对象的魔法方法__str__,打印结果为该方法返回值
# 所以可以推断出实例化异常对象时,传入的"This is a ZeroDivisionError"
# 实际就是魔法方法__str__的返回值
ins = ZeroDivisionError("This is a ZeroDivisionError")
print(ins)	

# 输出结果:This is a ZeroDivisionError


ins = ZeroDivisionError("This is a ZeroDivisionError")
describe_string = ins.__str__()		# 手动调用魔法方法__str__,打印该方法的返回值
print(describe_string)

# 输出结果:This is a ZeroDivisionError

data = 10
ins = ZeroDivisionError("This is a ZeroDivisionError, carry a data: %s" % data )
print(ins)	

# 输出结果:This is a ZeroDivisionError, carry a data: 10

在except语句中,可以使用 raise 语句,将raise语句的exception部分留空,这会将当前被处理的 Python 异常重新抛出(引发)

但是以上做法的效果并不等同于调用exception函数的语句raise sys.exception(),或类似于raise err的语句(假设err为as关键字绑定的标识符),他们会展示不同的回溯(Traceback)信息

python 复制代码
# calculate.py文件的内容
def divide(a, b):	# 进行除法运算的函数
    return a / b

# main.py文件的内容
from calculate import divide

divide(5, 0)

# 抛出异常:
"""
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 3, in <module>
    divide(5, 0)
  File "C:\编程\Python代码\test\calculate.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero
"""


# calculate.py文件的内容
def divide(a, b):	# 进行除法运算的函数
    return a / b

# main.py文件的内容
from calculate import divide

try:
    divide(5, 0)

except ZeroDivisionError:
    print("ZeroDivisionError异常被捕获")
    raise	# 使用raise重新抛出异常
    
# 抛出异常:
"""
ZeroDivisionError异常被捕获
Traceback (most recent call last):
  File "C:\编程\Python代码\test\test.py", line 4, in <module>
    divide(5, 0)
  File "C:\编程\Python代码\test\calculate.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero
"""


# calculate.py文件的内容
def divide(a, b):	# 进行除法运算的函数
    return a / b

# main.py文件的内容
from calculate import divide

try:
    divide(5, 0)

except ZeroDivisionError as e:
    print("ZeroDivisionError异常被捕获")
    raise e	
   
# 抛出异常:
"""
ZeroDivisionError异常被捕获
Traceback (most recent call last):
  File "C:\编程\Python代码\test\test.py", line 8, in <module>
    raise e
  File "C:\编程\Python代码\test\test.py", line 4, in <module>
    divide(5, 0)
  File "C:\编程\Python代码\test\calculate.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero
"""

抛出异常时,自动创建的异常对象的魔法方法__str__的返回值即为 traceback 最后一行针对该异常的描述信息

python 复制代码
5 / 0

# 抛出异常:
"""
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 1, in <module>
    5 / 0
ZeroDivisionError: division by zero
"""


try:
    5 / 0

except ZeroDivisionError as e:
	# 判断 e 是否为ZeroDivisionError的实例对象
    flag = isinstance(e, ZeroDivisionError)
    print(flag)
	
	# 手动调用魔法方法__str__,打印该方法的返回值,进行对比
    describe_string = e.__str__()	
    print(e)
    print(describe_string)

# 输出结果:
"""
True
division by zero
division by zero
"""


try:
    5 / 0

except ZeroDivisionError as e:
    print("自动抛出的异常被捕获")
    raise e

# 输出结果:
"""
自动抛出的异常被捕获
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 6, in <module>
    raise e
  File "C:\编程\Python代码\test\main.py", line 2, in <module>
    5 / 0
ZeroDivisionError: division by zero
"""

自行创建一个异常对象,通过raise抛出,同时携带自定义的描述信息

python 复制代码
try:
    5 / 0

except ZeroDivisionError as e:
    print("自动抛出的异常被捕获")
    raise ZeroDivisionError("<division by zero>")

# 输出结果:
"""
自动抛出的异常被捕获
Traceback (most recent call last):
  File "C:\编程\Python代码\test\main.py", line 6, in <module>
    raise ZeroDivisionError("<division by zero>")
ZeroDivisionError: <division by zero>
"""

raise...from 语句

如果一个 Python 异常已经被某个except语句处理,而该except语句的相关代码引发了新的异常,如果新的 Python 异常是通过raise...from语句引发,那么可以为新的 Python 异常指定一个表示原因的异常,用于说明新的 Python 异常是由该异常导致的

raise...from语句可以在其他位置使用,如果位于except语句的相关代码中,那么表示原因的异常一般被指定为已被except处理的 Python 异常,此时回溯信息将优先展示表示原因的 Python 异常的信息

python 复制代码
raise...from 语句基本的语法形式为 raise <newexception> from <causeexception>
  • newexception

    • 被抛出的 Python 异常对象,或 Python 异常类型。如果仅给出异常类型,那么将根据该类型隐式创建其对应的实例,比如,raise RuntimeError from ValueError()的效果等同于raise RuntimeError() from ValueError()
  • causeexception

    • 表示原因的 Python 异常对象,或 Python 异常类型。如果仅给出异常类型,那么将根据该类型隐式创建其对应的实例,比如,raise RuntimeError() from ValueError的效果等同于raise RuntimeError() from ValueError()

Python 异常的基类 BaseException

在 Python 中,所有异常(表示异常的类)都需要继承自BaseException或Exception,这包括 Python 的内置异常,以及由开发人员定义的异常(当然,只有少数 Python 异常直接继承自类BaseException,大部分 Python 异常均继承自类Exception或类Exception的派生类)

  • Python 异常基类 BaseException 和 Exception 之间的区别
    • Exception是BaseException类的派生类,他表示不是来自于系统的非正常情况,比如,表示除数为0的 Python 异常ZeroDivisionError
    • 一般情况下,开发人员仅需要捕获从Exception类派生的各种 Python 异常,如果将捕获的范围扩大到BaseException,那么可能会导致一些意想不到的问题
    • 如果except后没有指定异常类型,则默认捕获所有的异常,即此时捕获异常范围为BaseException, 这样的没有指定异常类型的 except 语句要求必须是最后一个 except 语句,否则程序报错,原因很简单,如果它位于其他except语句之前,那么一些except语句将失去被执行的可能

如果将捕获异常的范围扩大到BaseException,可能会导致sys.exit()无法退出 Python 解释器

python 复制代码
import sys

try:
	sys.exit()	# 尝试退出程序
except BaseException as e:
	print(f'捕获到了异常 {type(e)}')

print('sys.exit() 已经执行,但是程序没有成功退出')

# 输出结果:
"""
捕获到了异常 <class 'SystemExit'>
sys.exit() 已经执行,但是程序没有成功退出
"""
相关推荐
明月清风徐徐4 分钟前
Scrapy爬取豆瓣电影Top250排行榜
python·selenium·scrapy
theLuckyLong5 分钟前
SpringBoot后端解决跨域问题
spring boot·后端·python
Yongqiang Cheng8 分钟前
Python operator.itemgetter(item) and operator.itemgetter(*items)
python·operator·itemgetter
MavenTalk11 分钟前
Move开发语言在区块链的开发与应用
开发语言·python·rust·区块链·solidity·move
FksLiao23 分钟前
Superset安装
python
L Jiawen30 分钟前
【Python · PyTorch】卷积神经网络(基础概念)
pytorch·python·cnn
goomind35 分钟前
深度学习模型评价指标介绍
人工智能·python·深度学习·计算机视觉
->yjy44 分钟前
wordcloud库基本介绍
python
2401_840192271 小时前
python基础大杂烩
linux·开发语言·python
abments1 小时前
JavaScript逆向爬虫教程-------基础篇之常用的编码与加密介绍(python和js实现)
javascript·爬虫·python