Python零基础入门-8 错误和异常

简介: Python零基础入门-8 错误和异常

8.错误和异常

8.1 常见报错

程序中经常会出错,常见的错误包括但不限于:

  • 语法错误:“SyntaxError:invalid syntax”
  • 异常:xxError,如NameError、TypeError、IndentationError、ModuleNotFoundError等

语法错误,在运行前就可以发现。如果使用PyCharm会有红色波浪线提醒你,请检查拼写缩进符号等是否符合语法。(SyntaxError也是一种异常,但是因为它比较特殊,在运行前就可以检查出来,所以单独说。)


异常情况很多,需要根据报错内容具体分析。下面我们看看异常到底是什么以及如何处理异常。

8.2 异常

程序执行时往往会出现预期之外的错误,也就是异常


这些错误未必是程序设计的问题,也可能是用户非法输入、网络问题等导致程序出错。

例如一个计算器程序,用户输入1/0的时候,0作分母是无意义的。因此程序无法正常执行,引发报错。

>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero


实际程序中,我们可能遇到各种异常。


内置异常 — Python 3.10.4 文档里提供了大多数可能的异常,如IO异常,迭代异常、编码错误异常等等。


BaseException是所有异常的基类,它可以用来捕获所有异常。


但更常用是Exception。Exception是所有内置的非系统退出类异常的基类。 所有用户自定义异常也应当派生自此类。

8.3 处理异常

8.3.1 try-except

一般用try-except 语句来提前预防错误。

语法格式:

try:
    ...
    执行一些可能出错的操作
except 异常类型:
    ...
    对出错进行一个说明和处理

例如,我们写了一个从用户输入读取a,b,并计算a/b的程序。

用户可能输入一个非数字内容,引发ValueError,也可能输入0作为除数,引发ZeroDivisionError

于是我们把可能出错的语句放在try里面,并且用 except捕捉错误。

try:
    a = int(input('a= '))
    b = int(input('b= '))
    print('a/b= ',a/b)
except (ValueError,ZeroDivisionError):
    print("无效输入,请重试")

try 语句的工作原理如下:

  • 首先,执行 try 子句
  • 如果没有触发异常,则跳过 except 子句try 语句执行完毕。
  • 如果在执行 try 子句时发生了异常,则跳过该子句中剩下的部分。 如果异常的类型与 except 关键字后指定的异常相匹配,则会执行 except 子句,然后跳到 try/except 代码块之后继续执行。如果发生的异常与 except 子句 中指定的异常不匹配,则它会被传递到外部的 try 语句中;如果没有找到处理程序,则它是一个 未处理异常 且执行将终止并输出报错信息。except 子句 可以用带圆括号的元组来指定多个异常,例如:
except (RuntimeError, TypeError, NameError):
    pass

try后面可以接多个except,来捕获多种异常。如果异常被前面的except捕获了,则后面的except不会继续执行:

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print(err.args)
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except BaseException as err:
    print(f"Unexpected {err=}, {type(err)=}")
    raise

except 子句 可以在异常名称后面用as指定一个变量。 这个变量会绑定到一个异常实例并将参数存储在 instance.args 中。 print(err)会调用异常类的__str__() 方法,获取表示异常的字符串。

8.3.2 try-except-else

tryexcept 语句具有可选的 else 子句,该子句如果存在,它必须放在所有 except 子句 之后。 else会在 try 子句 没有引发异常时执行。 例如:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except OSError:
        print('cannot open', arg)
    else:    #如果没有异常,则读取文件
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

8.3.3 try-…-finally

try 语句还有一个可选子句finally,用于定义在所有情况下都必须要执行的清理操作。例如:

try:
    raise KeyboardInterrupt
finally:
    print('Goodbye, world!')

不论 try 语句是否触发异常,都会执行 finally 子句。在实际应用程序中,finally 子句对于释放外部资源(例如文件或者网络连接)非常有用。

with 语句是try-finally的一种简化写法,相当于在后面隐藏了一个finally来清理资源:

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

try-finally 特殊情形:

以下内容介绍了几种比较复杂的触发异常情景:

  • 如果执行 try 子句期间触发了某个异常,则某个 except 子句应处理该异常。如果该异常没有 except 子句处理,在 finally 子句执行后会被重新触发。
  • exceptelse 子句执行期间也会触发异常。 同样,该异常会在 finally 子句执行之后被重新触发。
  • 如果 finally 子句中包含 breakcontinuereturn 等语句,异常将不会被重新引发。
  • 如果执行 try 语句时遇到 break,、continuereturn 语句,则 finally 子句在执行 breakcontinuereturn 语句之前执行。
  • 如果 finally 子句中包含 return 语句,则返回值来自 finally 子句的某个 return 语句的返回值,而不是来自 try 子句的 return 语句的返回值。

8.4 抛出异常

8.4.1 raise 异常

raise语句可以抛出指定的异常:

raise 异常

raise NameError('HiThere')


在捕获异常后如果不想处理,可以用单个raise重新抛出异常:

try:
    raise NameError('HiThere')
except NameError:
    print('An exception flew by!')
    raise

8.4.2 异常链 raise from

raise 支持可选的 from子句,用于启用链式异常。

如:raise RuntimeError from exc

转换异常时,这种方式很有用。例如:

def func():
    raise ConnectionError

try:
    func()
except ConnectionError as exc:
    raise RuntimeError('Failed to open database') from exc

异常链会在 exceptfinally 子句内部引发异常时自动生成。 这可以通过使用 from None 这样的写法来禁用:

try:
    open('database.sqlite')
except OSError:
    raise RuntimeError from None

8.3 用户自定义异常

用户可以通过自定义继承Exception的类来实现自己的异常。大多数异常命名都以 “Error” 结尾,类似标准异常的命名。(第9章类将介绍如何定义类)

class MyError(Exception):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)
try:
    raise MyError(42)
except MyError as e:
    print(e)
相关文章
|
22天前
|
测试技术 开发者 Python
对于Python中的异常要如何处理,raise关键字你真的了解吗?一篇文章带你从头了解
`raise`关键字在Python中用于显式引发异常,允许开发者在检测到错误条件时中断程序流程,并通过异常处理机制(如try-except块)接管控制。`raise`后可跟异常类型、异常对象及错误信息,适用于验证输入、处理错误、自定义异常、重新引发异常及测试等场景。例如,`raise ValueError(&quot;Invalid input&quot;)`用于验证输入数据,若不符合预期则引发异常,确保数据准确并提供清晰错误信息。此外,通过自定义异常类,可以针对特定错误情况提供更具体的信息,增强代码的健壮性和可维护性。
|
20天前
|
Python
在Python中,`try...except`语句用于捕获和处理程序运行时的异常
在Python中,`try...except`语句用于捕获和处理程序运行时的异常
38 5
|
21天前
|
Python
在Python中,自定义函数可以抛出自定义异常
在Python中,自定义函数可以抛出自定义异常
33 5
|
21天前
|
存储 开发者 Python
自定义Python的异常
自定义Python的异常
13 5
|
2月前
|
存储 索引 Python
|
2月前
|
Python
Python生成器、装饰器、异常
【10月更文挑战第15天】
|
5月前
|
Unix API Python
【Python】已完美解决:(Python3.8异常)AttributeError: module ‘time‘ has no attribute ‘clock‘
【Python】已完美解决:(Python3.8异常)AttributeError: module ‘time‘ has no attribute ‘clock‘
107 0
|
2月前
|
设计模式 安全 JavaScript
Python学习八:面向对象编程(下):异常、私有等
这篇文章详细介绍了Python面向对象编程中的私有属性、私有方法、异常处理及动态添加属性和方法等关键概念。
26 1
|
3月前
|
人工智能 数据可视化 搜索推荐
Python异常模块与包
Python异常模块与包
|
2月前
|
开发者 索引 Python
Python常见的异常总结
Python 中的异常是一个非常广泛的主题,因为它包含许多内置的异常类型,这些类型可以处理各种运行时错误。
30 0