首页 > 其他分享 >错误处理

错误处理

时间:2024-07-09 16:56:05浏览次数:13  
标签:... 错误 except try finally print 错误处理

声明:此随笔内容摘抄自廖雪峰的官方网站,仅供自我学习,如侵权,请告知。


在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因。在操作系统提供的调用中,返回错误码非常常见。比如打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1。

但是用错误码来表示是否出错十分不便,因为函数本身应该返回的正常结果和错误码混在一起,造成调用者必须用大量的代码来判断是否出错:

def foo():
    r = some_function()
    if r==(-1):
        return (-1)
    # do something
    return r

def bar():
    r = foo()
    if r==(-1):
        print('Error')
    else:
        pass

一旦出错,还要一级一级上报,直到某个函数可以处理该错误(比如,给用户输出一个错误信息)。

所以高级语言通常都内置了一套try...except...finally...的错误处理机制,Python也不例外。

try

让我们用一个例子来看看try的机制:

try:
    print('try...')
    r = 10 / 0
    print('result:', r)
except ZeroDivisionError as e:
    print('except:', e)
finally:
    print('finally...')
print('END')

当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。

上面的代码在计算10 / 0时会产生一个除法运算错误:

try...
except: division by zero
finally...
END

从输出可以看到,当错误发生时,后续语句print('result:', r)不会被执行,except由于捕获到ZeroDivisionError,因此被执行。最后,finally语句被执行。然后,程序继续按照流程往下走。

如果把除数0改成2,则执行结果如下:

try...
result: 5
finally...
END

由于没有错误发生,所以except语句块不会被执行,但是finally如果有,则一定会被执行(可以没有finally语句)。

错误有很多种类,如果发生了不同类型的错误,应该由不同的except语句块处理。可以有多个except来捕获不同类型的错误:

try:
    print('try...')
    r = 10 / int('a')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
finally:
    print('finally...')
print('END')

int()函数可能会抛出ValueError,所以我们用一个except捕获ValueError,用另一个except捕获ZeroDivisionError。

如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:

try:
    print('try...')
    r = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。比如:

try:
    foo()
except ValueError as e:
    print('ValueError')
except UnicodeError as e:
    print('UnicodeError')

第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。

Python所有的错误都是从BaseException类派生的,常见的错误类型和继承关系看这里

使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用bar(),bar()调用foo(),结果foo()出错了,这时,只要main()捕获到了,就可以处理:

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        print('Error:', e)
    finally:
        print('finally...')

也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally的麻烦。

调用栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。来看看err.py:

# err.py:
def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    bar('0')

main()

执行,结果如下:

$ python3 err.py
Traceback (most recent call last):
  File "err.py", line 11, in <module>
    main()
  File "err.py", line 9, in main
    bar('0')
  File "err.py", line 6, in bar
    return foo(s) * 2
  File "err.py", line 3, in foo
    return 10 / int(s)
ZeroDivisionError: division by zero

出错并不可怕,可怕的是不知道哪里出错了。解读错误信息是定位错误的关键。我们从上往下可以看到整个错误的调用函数链:

错误信息第1行:

Traceback (most recent call last):

告诉我们这是错误的跟踪信息。

第2~3行:

  File "err.py", line 11, in <module>
    main()

调用main()出错了,在代码文件err.py的第11行代码,但原因是第9行:

  File "err.py", line 9, in main
    bar('0')

调用bar('0')出错了,在代码文件err.py的第9行代码,但原因是第6行:

  File "err.py", line 6, in bar
    return foo(s) * 2

原因是return foo(s) * 2这个语句出错了,但这还不是最终原因,继续往下看:

  File "err.py", line 3, in foo
    return 10 / int(s)

原因是return 10 / int(s)这个语句出错了,这是错误产生的源头,因为下面打印了:

ZeroDivisionError: integer division or modulo by zero

根据错误类型ZeroDivisionError,我们判断,int(s)本身并没有出错,但是int(s)返回0,在计算10 / 0时出错,至此,找到错误源头。

出错的时候,一定要分析错误的调用栈信息,才能定位错误的位置

标签:...,错误,except,try,finally,print,错误处理
From: https://www.cnblogs.com/wydz/p/18292195

相关文章

  • 深入 Laravel 的错误处理与异常处理机制
    引言Laravel是一个优雅而强大的PHPWeb应用框架,它提供了一系列工具来帮助开发者处理应用中的错误和异常。了解Laravel的错误处理和异常处理机制对于构建健壮和用户友好的应用程序至关重要。本文将深入探讨Laravel如何实现错误和异常处理,并提供一些实际的代码示例。......
  • FastAPI快速入门2 Pydantic&错误处理
    2.1Pydantic简介Pydantic使用python类型注解进行数据验证和配置管理。这是一款能让您更精确地处理数据结构的工具。例如,到目前为止,我们一直依赖字典来定义项目中的典型配方。有了Pydantic,我们可以这样定义配方:frompydanticimportBaseModelclassRecipe(BaseModel):id......
  • springboot Invalid bound statement (not found): com.elitel.xxx.dao.xxx 错误处
    如果这篇文章能给你带来帮助,不胜荣幸,如果有错误也请批评指正,一起学习,共同进步!今天给同事看了个问题,发现了这个问题,之前也遇见过,可是没有遇见这种情况,这次我记录一下。首先来说,造成这个错误的原因是什么。它是在SpringBoot应用程序中遇到“Invalidboundstatement(not......
  • PHP错误处理&异常处理方式小结
    PHP中的错误处理和异常处理是程序开发中非常重要的两个方面,它们可以帮助开发者识别和处理程序运行时出现的问题。以下是PHP中错误处理和异常处理的一些常见方式:错误处理错误级别:PHP定义了多种错误级别,如E_ERROR、E_WARNING、E_NOTICE等,通过设置错误级别,可以控制哪些错误会被......
  • 错误处理:fmt::Display & std::error::Error
    错误处理为什么要给错误类型(如JsonError)实现fmt::Displaytrait?在Rust中,fmt::Displaytrait允许你定义一个类型如何被格式化为人类可读的字符串。这通常用于错误信息、日志记录或任何其他用户输出。实现fmt::Display需要定义fmt函数,该函数写入特定格式的数据......
  • Java中的错误处理和日志记录:提升应用的健壮性和可维护性
            在Java开发中,有效的错误处理和日志记录是确保应用健壮性和可维护性的关键。通过恰当的异常处理和详尽的日志信息,开发者可以迅速定位和解决问题,同时提供程序运行的透明度。本文将探讨Java中的错误处理最佳实践和日志记录技术,包括常用的日志框架和配置方法。###......
  • C标准库的错误处理机制
    引言在C语言编程中,错误处理是确保程序健壮性和稳定性的重要部分。C标准库提供了一系列工具和函数,帮助开发者检测、报告和处理错误。本文将详细探讨C标准库的错误处理机制,包括标准错误处理函数、异常处理、错误代码以及错误处理的最佳实践。第一章:C标准库中的错误处理基础C......
  • 【C++】C++异常处理精要:从传统C语言错误处理到现代C++异常机制
    文章目录前言:1.C语言传统的处理错误的方式2.什么是异常处理机制?3.C++异常处理语法3.1.异常抛出(Throw)3.2.异常捕获(Catch)3.3.异常传递(ExceptionPropagation)3.4.异常规范(ExceptionSpecification)3.5.异常安全(Exceptionsafe)4.C++异常处理的最佳实践4.1.只在必......
  • C# 错误处理
    在C#中,System命名空间下预定义的一些常见的异常类型:Exception-所有异常的基类。ApplicationException-应用程序自定义异常的基类(不推荐使用,因为从.NETFramework4.0开始,建议使用Exception)。InvalidOperationException-当对象或方法处于不适当的状态时引发。ArgumentEx......
  • Rust 错误处理
    rust处理错误,不使用trycatch,而是使用Result<T,E>。简单的处理rust错误在各种关于rust错误处理的文档中,为了解释清楚其背后的机制,看着内容很多,不好理解。比如我们写一个方法,读取文件内容:fnread_file_to_string(file_path:String)->Result<String,io::Error>{le......