Exception和Raise的异常处理

异常

学习python到现在,我们已经遇到过很多的报错信息,但一直没有认真研究,现在我们认真的研究一下:python一般会出现哪些错误呢?这些错误出现以后,我们该如何处理它们?

错误

Python三种常见的错误类型

  • 语法错误(syntax error)
  • 逻辑错误(logic error)
  • 执行期间错误(runtime error)

比如:

>>> for i in range(10)
  File "<stdin>", line 1
    for i in range(10)
                     ^
SyntaxError: invalid syntax
>>>

​ 上面那句话因为缺少冒号:,导致解释器无法解释,于是报错。这个报错行为是由 Python 的语法分析器完成的,并且检测到了错误所在文件和行号(File “”, line 1),还以向上箭头^标识错误位置(后面缺少:),最后显示错误类型。

​ 当 Python 检测到一个错误时,解释器就无法继续执行下去,于是抛出异常。

异常错误

系统会根据不同的异错误,丢出不同的异常。

异常种类繁多,现简要举例:

看一个异常(让0做分母了,这是小学生都相信会有异常的):

>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>>
当 Python 抛出异常的时候,首先有“跟踪记录(Traceback)”,我们还可以给它取一个更优雅的名字——“回溯”。其后面显示异常的详细信息:比如异常所在位置(文件、行、在某个模块)。

最后一行是错误类型以及导致异常的原因。

下表中列出常见的异常

异常 描述
NameError 尝试访问一个没有申明的变量
ZeroDivisionError 除数为0
SyntaxError 语法错误
IndexError 索引超出序列范围
KeyError 请求一个不存在的字典关键字
FileNotFoundError 文件未发现错误(比如你要读的文件不存在)
AttributeError 尝试访问未知的对象属性
ModuleNotFoundError 模块未发现
IndentationError 缩进

举例说明:

# NameError
>>> test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'test' is not defined
# IndentationError
>>>   a=123
  File "<stdin>", line 1
    a=123
    ^
IndentationError: unexpected indent
# IndexError
>>> a="abd"
>>> a[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
 # ZeroDivisionError
>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
 # AttributeError  
>>> a=Car()
>>> a.color
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute 'color'
>>>
# ModuleNotFoundError
>>> import self_defin
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'self_defin'
>>>
# KeyError
>>> dict={"name":"ws"}
>>> dict["age"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'age'
>>>
#  FileNotFoundError
>>> a=open("w.txt","r")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'w.txt'
>>>
# SyntaxError
>>> for i in rang
  File "<stdin>", line 1
    for i in rang
                ^
SyntaxError: invalid syntax
>>>

当我们在运行或者调试程序时遇到了异常,我们要学会阅读异常信息,找到出错的位置,发现异常,并更正它。比如用 dir()help() 或者官方网站文档、google 等来协助,一定能解决问题。

异常处理

前面说,当 Python 检测到一个错误时,解释器就无法继续执行下去,于是抛出异常。

所以,在一段程序中,为了能够让程序健壮,必须要处理异常。

我们可以用try ... except来处理异常,其语法格式如下:

try:
	try_statements
except [Exception [as identifier]]:
	except_statements
[else:
	else_statements]
[finally:
	fanally_statements]
  • try子句
    • try … except 必须放在可能发生意外的程序段周围,而try_statements则是可能发生异常的程序段。
  • except子句
    • 用来捕捉指定的异常,一旦捕捉到,就执行与之对应的except_statements,即用来处理异常的程序语句。
    • 如果要针对不同的异常做不同的处理,可以使用多个except子句,其中,exceptionType是欲捕捉的异常类型,省略不写,表示为预设类型:BaseException,所有异常都继承自该类别。
    • [as identifier]可以将捕捉到的异常指向一个变量,然后,通过该变量获得异常相关的信息。
    • 不带任何异常类型使用except,将捕获所有发生的异常。不推荐这么使用,因为我们不能通过该程序识别出具体的异常信息。
  • else子句
    • 当try_statements没有异常发生时,会跳过except子句,执行else_statements。
    • 该子句为可选语句,可以指定或者省略。
  • finally子句
    • 当要离开try … except 时(无论异常是否发生),就会执行finally_statements,可以使清除错误或者收尾的语句。可给可忽略。

举个例子,编程求X/Y。

>>> x = eval(input("请输入被除数x:\t"))
请输入被除数x:  10
>>> y = eval(input("请输入除数y:\t"))
请输入除数y:    2
>>> z = x/y
>>> print("x/y=",z)

以上编程运行结果:

#第一种
C:\Users\asus\Desktop\pythondemo测试\python运行程序>python band.py
请输入被除数x:  10
请输入除数y:    2
x/y= 5.0
#第二种
C:\Users\asus\Desktop\pythondemo测试\python运行程序>python band.py
请输入被除数x:  12
请输入除数y:    0
Traceback (most recent call last):
  File "band.py", line 488, in <module>
    z = x/y
ZeroDivisionError: division by zero
#第三种
C:\Users\asus\Desktop\pythondemo测试\python运行程序>python band.py
请输入被除数x:  12
请输入除数y:    a
Traceback (most recent call last):
  File "band.py", line 487, in <module>
    y = eval(input("请输入除数y:\t"))
  File "<string>", line 1, in <module>
NameError: name 'a' is not defined
#第四种
C:\Users\asus\Desktop\pythondemo测试\python运行程序>python band.py
请输入被除数x:  12,
请输入除数y:    1
Traceback (most recent call last):
  File "band.py", line 488, in <module>
    z = x/y
TypeError: unsupported operand type(s) for /: 'tuple' and 'int'

除去第一种以外,均抛出异常,退出程序。

捕捉以上程序中的异常1:

try:
	x = eval(input("请输入被除数x:\t"))
	y = eval(input("请输入除数y:\t"))	
	z = x/y
# except ZeroDivisionError:    
# 	print("除数不能为0")
# except NameError:
# 	print("Name")
except (ZeroDivisionError,NameError,TypeError) as e:
	print((type(e)),e)
print("程序可以正常运行")

现在用try…except改写,并捕捉相应的异常信息,并做出对应的处理,使程序不会因为异常而中断

捕捉以上程序中的异常2:


try:
	x = eval(input("请输入被除数x:\t"))
	y = eval(input("请输入除数y:\t"))	
	z = x/y
except ZeroDivisionError:
	print("除数不能为0")
except Exception as e:
	print(e.args)
else:
	print("未捕捉到异常",z)
finally:
	print("离开try...except 模块")

try…except小结

  • 带有多个except的try语句z

    try:
    	...
    except exception1:
    	...
    except exception2:	
    	...
    
    • 处理多个异常的except语句
    try:
    	...
    except(exception1,exception2,...,)as e:
        ...
    
    • 捕获所有异常
    try:
    	...
    except Exception as e:
    	...
    
    try:
    	...
    except:
    	...
    

    raise(触发异常)

    除了系统抛出的异常,我们也可以使用raise语句自己触发异常。

    raise语法格式如下:

    raise [Exception [, args [, traceback]]]
    
    • Exception是异常的类型(例如,NumeError)参数标准异常任意一种
    • args是自己提供的异常参数
    • 最后一个参数是可选的(在实践中很少使用),如果存在,是跟踪异常对象。

    比如

    >>> raise NameError("Sorry,Error occurs")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: Sorry,Error occurs
    >>>
    

    也可以使用try…except来捕捉raise抛出的异常:

    >>> try:
    ...     raise NameError("Sorry,Error occurs")
    ... except NameError:
    ...     print("捕捉到 NameError")
    ...
    捕捉到 NameError
    >>>
    

    assert

    assert基本用法

    assert condition
    

    用来让程序测试这个condition,如果condition为false,那么raise一个AssertionError出来,逻辑上等同于:

    if not condition:
    	raise AssertionError()
    

    比如如下的例子:

    >>> assert 1==1
    >>> assert 1==0
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AssertionError
    >>>
    

    为assert断言语句添加异常参数
      assert的异常参数,其实就是在断言表达式后添加字符串信息,用来解释断言并更好的知道是哪里出了问题。格式如下:

    assert expression [, arguments]
    

    比如:

    >>> li=[1,2]
    >>> assert len(li)>=5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AssertionError  列表元素个数小于5
    >>>
    
    >>> assert 1==len(li)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AssertionError 1不等于2
    

    从上面的举例中可以基本了解了 assert 的特点。

    assert,翻译过来是“断言”之意。assert 是一句等价于布尔真的判定,发生异常就意味着表达式为假。

    assert 的应用情景就有点像汉语的意思一样,当程序运行到某个节点的时候,就断定某个变量的值必然是什么,或者对象必然拥有某个属性等,简单说就是断定什么东西必然是什么,如果不是,就抛出错误。

    这就是断言 assert 的引用。什么是使用断言的最佳时机?有文章做了总结:

    如果没有特别的目的,断言应该用于如下情况:

    • 防御性的编程
    • 运行时对程序逻辑的检测
    • 合约性检查(比如前置条件,后置条件)
    • 程序中的常量
    • 检查文档

猜你喜欢

转载自blog.csdn.net/w1359414/article/details/89669359
今日推荐