小白学python之错误处理_学习笔记

本文深入探讨Python中的错误处理机制,包括try...except...finally语句的使用,以及如何自定义异常类来增强代码的健壮性和可读性。通过实际案例,详细解析错误调用栈的分析方法,帮助读者理解并处理复杂错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文以廖雪峰的官方网站为参考来学习python的。其学习链接为廖雪峰小白学python教程

本文是学习到python的定制类。参考链接廖雪峰python错误处理

本学习笔记仅供参考。

笔记

在操作系统提供的调用中,返回错误码非常常见。

比如,打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1。

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

示例代码:

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

    return r

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

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

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

try

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

运行结果:

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

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')

运行结果:

try...
ValueError: invalid literal for int() with base 10: 'a'
finally...
END

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...')

调用栈

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

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

def main():
    bar('0')

main()

运行结果:

Traceback (most recent call last):
  File "*********", line **, in <module>
    main()
  File "***********", line **, in main
    bar('0')
  File "************", line **, in bar
    return foo(s) * 2
  File "***************", line **, in foo
    return 10 / int(s)
ZeroDivisionError: division by zero

 

笔记

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

错误信息第1行:

Traceback (most recent call last):

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

第2~3行:

File "*********", line **, in <module>
    main()

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

File "***********", line **, in main
    bar('0')

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

  File "************", line **, in bar
    return foo(s) * 2

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

  File "***************", line **, in foo
    return 10 / int(s)

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

ZeroDivisionError: division by zero

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

笔记:

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

记录错误

如果不捕获错误,自然可以让Python解释器来打印出错堆栈。但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因。同时,让程序继续执行下去。

 

Python内置的logging模块可以非常容易地记录错误信息:

import logging

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

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

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)

main()
print('END')

抛出错误

因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。

Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:

class FooError(ValueError):
    pass

def foo(s):
    n = int(s)
    if n==0:
        raise FooError('invalid value: %s' % s)
    return 10 / n

foo('0')

运行结果:

Traceback (most recent call last):
  File "****************", line *, in <module>
    foo('0')
  File "*****************", line *, in foo
    raise FooError('invalid value: %s' % s)
__main__.FooError: invalid value: 0

只有在必要的时候才定义我们自己的错误类型。入股偶可以选择Python已有的内置的错误类型(比如ValueError,TypeError),尽量使用Python内置的错误类型。

最后,我们来看另一种错误的处理的方式:


def foo(s):
    n = int(s)
    if n == 0 :
        raise ValueError('invalid value: %s' % s)
    return 10 / n

def bar():
    try:
        foo('0')
    except ValueError as e:
        print('ValueError!')
        raise

bar()

运行结果:

ValueError!
    foo('0')
  File "**************", line **, in foo
    raise ValueError('invalid value: %s' % s)
ValueError: invalid value: 0

# -*- coding: utf-8 -*-
from functools import reduce

def str2num(s):
    return int(s)

def calc(exp):
    ss = exp.split('+')
    ns = map(str2num, ss)
    return reduce(lambda acc, x: acc + x, ns)

def main():
    r = calc('100 + 200 + 345')
    print('100 + 200 + 345 =', r)
    r = calc('99 + 88 + 7.6')
    print('99 + 88 + 7.6 =', r)

main()

运行结果:

100 + 200 + 345 = 645
Traceback (most recent call last):
  File "******************", line **, in <module>
    main()
  File "******************", line **, in main
    r = calc('99 + 88 + 7.6')
  File "******************", line **, in calc
    return reduce(lambda acc, x: acc + x, ns)
  File "******************", line *, in str2num
    return int(s)
ValueError: invalid literal for int() with base 10: ' 7.6'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

碰珺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值