🏠大家好,我是Yui_,目标成为全栈工程师~💬 🍑如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 🚀如有不懂,可以随时向我提问,我会全力讲解~ 🔥如果感觉博主的文章还不错的话,希望大家关注、点赞、收藏三连支持一下博主哦~! 🔥你们的支持是我创作的动力! 🧸我相信现在的努力的艰辛,都是为以后的美好最好的见证! 🧸人的心态决定姿态! 💬欢迎讨论:如有疑问或见解,欢迎在评论区留言互动。 👍点赞、收藏与分享:如觉得这篇文章对您有帮助,请点赞、收藏并分享!
🚀分享给更多人:欢迎分享给更多对编程感兴趣的朋友,一起学习!

1. 什么是异常

在编程中,异常(Exception)是指程序在运行过程中程序的错误或者意外情况,它会导致程序的控制流发生改变。通常,异常发生时程序会停止正常执行,直到找到能够处理该异常的代码或者终止程序的执行。 异常

1.1 异常的特点

  • 意外事件:异常是程序在运行过程中的预料之外的事情,经典的案例有:除0错误,文件为找到,网络连接中断等等。
  • 中断程序流:一旦发生异常,程序的正常执行会被中断,直到异常被捕获并处理或者程序崩溃。
  • 可捕获和处理:通过异常处理机制,可以捕获异常并进行处理,从而防止程序完全崩溃。

1.2 异常的类型

python提供了很多常见的内建异常类型,用于表示不同的错误类型。例如:

  • ZeroDivisionError:除0错误。
  • FileNotFoundError:文件未找到错误。
  • ValueError:值错误,通常发生在类型不匹配时。
  • IndexError:索引超出范围错误。 ..... 了解完异常后,下面就是异常的处理了。

2. 如何进行异常处理

Python 的异常处理机制主要通过 tryexceptelsefinally 语句来实现。其目的是捕获程序中可能出现的错误(异常),并进行相应处理,避免程序崩溃。 具体可以分为三步:

  1. 抛出异常:当程序遇到异常情况时,会抛出异常。抛出异常时,程序控制流会被转移到最近的异常处理代码。
  2. 捕获异常:通过try-except语句,我们可以捕获并处理异常,当异常发生时,程序会跳转到与之匹配的except块进行处理。
  3. 处理异常:处理异常的方式可以是记录错误日志,提供用户友好的错误信息、恢复程序的状态等。处理完异常后,程序可以继续执行或根据需求终止。 那么先来介绍相关的关键字吧

2.1 try语句

try块用于编写可能会抛出异常的代码。如果代码执行过程中发生异常,python会跳转到相应的except块进行处理。 写一个除0错误来看看吧

try:
    x = 1/0 #除0错误,抛出ZeroDivisionError异常
except ZeroDivisionError as e:
    print('除0错误:',e) #输出:除0错误: division by zero

2.2 except语句

except块用于捕获异常并处理它。可以指定捕获某一特定类型的异常,或者捕获所有异常。

try:
    x = 1/0
except ZeroDivisionError as e:
    print('除0错误',e) #除0错误: division by zero

捕获多个不同类型的异常:

try:
    x = int("string")
except (ValueError,TypeError) as e:
    print('错误类型:',e) #错误类型: invalid literal for int() with base 10: 'string'

捕获所有异常(不推荐,除非有充分的理由)

try:
    #x = 1/0
    x = int("string")
except Exception as e:
    print('发生了一个异常:',e) #发生了一个异常: invalid literal for int() with base 10: 'string'

直接捕获 Exception 会导致一系列潜在问题,比如掩盖程序中的真实错误、影响程序的退出、难以针对特定错误做处理等。因此,推荐捕获特定的异常类型,确保程序能够精准地处理不同类型的错误,并且保持程序的可调试性、可维护性和灵活性。

2.3 else语句

else块在try块没有抛出异常时执行。如果try中的代码正常执行(没有异常),则会执行else中的代码。

try:
    x = 1/2
except ZeroDivisionError as e:
    print('除0错误')
else:
    print(f'x = {x}') #输出0.5

2.4 finally语句

finally块用于执行一些清理工作,不管是否发生异常都会执行。它通常用于关闭文件,释放资源等操作。

try:
    file = open('text.txt','r')
    content = file.read()
except FileNotFoundError as e:
    print('文件不存在:',e)
finally:
    print('无论是否发生异常,都会执行此处的代码')
    file.close()
'''
打印结果:
文件不存在: [Errno 2] No such file or directory: 'text.txt'
无论是否发生异常,都会执行此处的代码
Traceback (most recent call last):
  File "d:\code\python\abnormal\finally.py", line 8, in <module>
    file.close()
    ^^^^
NameError: name 'file' is not defined. Did you mean: 'filter'?
'''

报错

2.5 自定义错误

python运行通过继承Exception类来定义自定义的异常类型。

class MyCustomError(Exception):
    pass
try:
    raise MyCustomError('这是一个自定义异常') #主动抛出异常,raise类似于java中的throw
except MyCustomError as e:
    print(f'捕获到自定义异常:{e}') #输出捕获到自定义异常:这是一个自定义异常

2.6 上下文管理器(with语句)

上下文管理器是执行代码是自动处理资源(如文件、网站连接等)的方式。通过自定义上下文管理器,可以确保在代码块执行前后自动处理异常。 例如,with语句常用于文件操作,能够自动管理文件的打开和关闭:

# 使用 `with` 语句来打开文件,确保在使用完后自动关闭文件
with open("example.txt", "r") as file:
    content = file.read()
    print(content)

2.7 使用traceback模块获取更多异常信息

traceback 模块提供了用于获取异常详细信息的函数。你可以通过 traceback.format_exc() 获取详细的异常堆栈跟踪信息,这对于调试非常有帮助。

import traceback

try:
    1 / 0
except Exception as e:
    print("发生错误:", e)
    print("堆栈跟踪:", traceback.format_exc())
'''
打印结果:
发生错误: division by zero
堆栈跟踪: Traceback (most recent call last):
  File "d:\code\python\abnormal\Tre.py", line 4, in <module>
    1 / 0
    ~~^~~
ZeroDivisionError: division by zero
'''

获取更多异常信息

Python 的异常处理机制通过 try-except 语句让我们能够优雅地捕获和处理错误,确保程序在面对意外问题时不会崩溃,同时也能让我们在出错时进行适当的错误日志记录和资源清理。 你有没有想过既然我们已经知道了会发生什么类型的错误,为什么不把程序写对,还搞什么异常处理呢?其实可没这么简单哦~

3. 为什么要进行异常处理

在编程中,知道某些存在会发生异常并不总是意味着我们应该通过修改代码来避免这些异常。实际上,在很多情况下,异常处理是一种更加优雅且有效的解决方案。以下我会给出原因,为什么在已知可能会发生异常时,我们会选择进行异常处理而不是修改代码。

3.1 有些错误无法避免

有些异常是程序执行过程中无法避免的,比如:

  • 用户输入的非法数据(如数字输入要求,但是用户输入字符)。
  • 外部资源不可用(比如文件不存在,网络连接丢失,数据库连接失败)。
  • 时间和空间的限制(比如内存不足,文件过大等等)。

3.2 异常使得代码更加灵活

有时,异常发生并不意味着程序的失败,而是为了在某些意外情况下采取灵活的行动。程序的设计常常需要具备容错性和灵活性。

  • 外部依赖不可控:许多系统依赖于外部输入或服务,而这些服务不一定总是可靠。例如,文件是否存在、外部服务是否响应、用户是否输入有效数据等。
  • 不同的错误响应:有些错误我们希望通过恢复操作(如重试、使用备用方案)来解决,而有些错误则需要终止程序。 例如,如果数据库连接失败,可以通过异常处理捕获该异常,然后进行重试或者使用备用数据库;如果文件不存在,可以让用户提供路径,而不是直接退出程序。

3.3 避免过度复杂的代码修改

如果所有的潜在异常都要通过修改代码来避免,程序的复杂性将急剧增加。每个细节都需要为可能的错误情况添加检查,这会让代码变得臃肿且不易维护。 例如,检查用户输入是否有效,验证文件是否存在、数据库连接是否正常等,可以通过异常处理来集中管理错误,而不需要将大量的“防错”代码散布在程序中。

# 复杂的代码修改(不是很优雅)
if file_exists(filename):
    open_file(filename)
else:
    print("文件不存在")

# 使用异常处理(简洁优雅)
try:
    open_file(filename)
except FileNotFoundError:
    print("文件不存在")

总的来说,虽然修改代码以避免异常是一种常见的处理方式,但并不是每次都能满足需求。异常处理提供了一种更加灵活、清晰和优雅的方式来应对错误,尤其在面对外部输入、环境变化等不可控因素时。通过异常处理,程序不仅可以更好地容忍错误,还能保持稳定和可维护性。

4. 异常和Bug有什么区别

你有没有想过异常和Bug有什么区别呢?

  • **异常(Exception)**:
    • 是程序在运行时遇到的错误或异常情况,通常会中断程序的正常流程。
    • 异常是由程序内部逻辑、环境问题或外部输入等原因引起的,开发者可以通过异常处理机制(如 try-except)来捕获并处理它们。
    • 异常通常是预期的错误,程序员可以预测并进行相应处理。 例如:FileNotFoundErrorZeroDivisionError
  • Bug
    • Bug 是程序中的缺陷、错误或设计不当,通常是由于程序员在编写代码时的疏忽、逻辑错误或误解需求导致的。
    • Bug 不一定是异常,它可能不会直接引发程序崩溃,但会导致程序的行为不符合预期。
    • Bug 是不期望的错误,需要通过调试和修复来解决。 例如:错误的算法实现、用户界面问题、数据处理中的逻辑错误。 一句话来说就是:异常是程序运行过程中遇到的错误,通常是可以被捕获和处理的;而bug是程序代码中的缺陷或设计问题,可能导致程序行为不符合预期,通常需要通过调试来修复。

5.总结

异常处理不仅仅是程序中应对错误的工具,更是确保程序健壮性和可维护性的重要手段。通过精确地捕获和处理异常,开发者能够有效地防止程序崩溃,并为用户提供更加友好的错误提示。合理的异常处理不仅能让代码在面对预期之外的情况时保持稳定,还能提升程序的可读性与可扩展性。无论是基础的异常捕获,还是进阶的自定义异常设计和上下文信息的传递,异常处理的每一层细节都关系到代码的质量和系统的可靠性。通过不断优化异常处理机制,我们不仅能提升用户体验,还能为程序的未来发展打下坚实的基础。掌握并善用异常处理技巧,将使我们的代码更加优雅、可靠,真正能够应对复杂多变的实际应用场景。

文章代码:gitee 异常处理