pythontry参数_python: 错误处理try详解 ,traceback调用栈, 调试(logging)

错误处理

调试

新增:2020-01-19 增加关于文件读取的方法tell(), seek()等知识。

错误处理

高级语言都会使用内置的一套try...except...finally...的错误处理机制, 可以更高效的处理错误,

无需程序员自己写错误处理的代码。

try

try:print('try...')

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

如果有错误,根据发生不同类型的错误,使用不同的except处理。

int('a')会出发 ValueError

10/0会触发ZeroDivisionError。

如果没有找到expect匹配的异常,则将异常传递到外部的try语句中。会显示traceback

否则代表没有错误,则执行else。

无论是否发生异常,最后都要执行finally

常见的错误类型和继承关系

看文档Built-in Exceptions

try的好处

可以处理try子句中调用(间接调用)的函数内部发生的异常,即跨多层调用。

函数main()调用bar(), bar调用foo(), 只要期间发生错误,try就会处理。

deffoo(s):return 10 /int(s)defbar(s):return foo(s) * 2

defmain():try:

bar('0')exceptException as e:print('Error:', e)finally:print('finally...')

调用栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序终止。

错误信息是Traceback (most recentcalllast)...。它是一个错误路径。可以在最后查看错误原因,定位错误位置。

例子:

importsystry:

f= open('example.log', 'r+')

s=f.readline()

i=int(s.stripd())exceptOSError as err:print("OS error: {}".format(err))exceptValueError:print("Could not convert datga to a integer")except:print("Unexpected error", sys.exc_info()[0])raise

else:print(i)#OSError类, 就是IOError的别名。输入输出错误类.会升起和系统错误代码香港的错误。包括很多子类

#最后的excepte没有指定异常类,当作通配符用。#sys.exc_info会返回,当前正在处理的exception的信息:#返回的值是一个tuple:包括3个value。(type, value, traceback), 如果没有对应的值返回None。

#example.log

213

1

解释:

f = open(), 使用内建方法open。open其实是io模块的方法。

s = f.readline(), 会把example.log文件的第一行代码返回给变量s。

s.stripd(),这是❌的拼写,多写了一个字面d,系统有内置函数strip(),所以要去掉字母d,否则会执行exept子句。

代码最后一个except子句没有异常类,所以向上级抛错误。

sys.exc_info():这个方法是sys模块的方法。用法见注释。

本例子返回的是:

Unexpected error Traceback (most recent call last):

File"linshi.py", line 6, in i=int(s.stripd())

AttributeError:'str' object has no attribute 'stripd'

except子句的as

except Exception as inst:

as 后面的inst变量和产生的异常类的实例绑定,如果异常实例有参数,使用inst.args查看。

因为异常类BaseException类定义了object.__str__(self)方法, 这个方法返回对象自身的字符串格式,所以可以直接使用inst,查看错误。

例子:

defthis_fails():

x= 1/0try:

this_fails()exceptZeroDivisionError as err:print("Handing run-time error:", err.args)print("Handing run-time error:", err)#返回:

Handing run-time error: ('division by zero',)

Handing run-time error: division by zero

logging模块

可以把错误信息记录到日志。并让程序继续执行。

#err_logging.py

importloggingdeffoo(s):return 10 /int(s)defbar(s):return foo(s) * 2

defmain():try:

bar('0')exceptException as e:

logging.exception(e)

main()print('END')

抛出异常 raise语句

raise(参数), 参数是异常类或者它的实例。如果参数是异常类,它会通过调用构造函数来暗中/隐式实例化。

内置函数有各种类型的错误。也可以自己编写函数,然后抛出错误。

#err_raise.py

classFooError(ValueError):pass

deffoo(s):

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

foo('0')

编写一个错误类FooError。

用raise语句,生成FooError的实例。

尽量使用内置的函数。如ValueError, TypeError

最常用的错误处理方式:try...except...并调用一个单独的raise。

目的:

用except捕获指定❌

然后,用raise语句进行trackback。

下面代码:注释掉了raise,所以最后结果不会显示Traceback (most recent call last)的信息。

from functools importreducedefstr2num(s):returnint(s) #改为float(s)即可纠正错误defcalc(exp):

ss= exp.split('+')

ns=map(str2num, ss)return reduce(lambda acc, x: acc +x, ns) #functools的方法reduce(function, iterable)defmain():try:

r= calc('99 + 88 + 7.6')print('99 + 88 + 7.6 =', r)exceptValueError as e:print(">>>%s" %e)#raise

main()

加上单独的raise的作用,就是把当前错误原样抛出,可进行后续的追踪。

由于当前函数不知道应该怎么处理该错误,所以,继续往上抛错误,让顶层调用者去处理。

如果raise带了不同的异常类实例的参数,,可以把一种类型的错误转化为另一种类型:

try:10 /0exceptZeroDivisionError:raise ValueError('input error!')

finally的作用

finally是try语句的可选子句,它不论是否产生异常都会执行。用于定义清理操作。

但有几点特殊情况,执行的时间不一样。具体可见文档: 8.6. 定义清理操作

调试

第一种方法简单直接粗暴有效,就是用print()把可能有问题的变量打印出来看看。

第二种:print()但看完还要删除,因此可以用assert。

不用了,可以在启动时,带上参数-O关掉assert的功能。

#err.py

deffoo(s):

n=int(s)assert n != 0, 'n is zero!'

return 10 /ndefmain():

foo('0')

main()

$ python -O err.py

注意是大写的字母O,

第三种logging。

importlogging

logging.basicConfig(level=logging.INFO) #进行配置,logging级别,默认是WARNING,所以INFO,DEBUG级别的不会被追踪

s= '0'n=int(s)

logging.info('n= %d' %n)print(10/0)

这就是logging的好处,它允许你指定记录信息的级别。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。

级别何时使用

DEBUG

细节信息,仅当诊断问题时适用。

INFO

确认程序按预期运行

WARNING

表明有已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行

ERROR

由于严重的问题,程序的某些功能已经不能正常执行

CRITICAL

严重的错误,表明程序已不能继续执行

默认的级别是``WARNING``,意味着只会追踪该级别及以上的事件,除非更改日志配置。

追踪的事件可以:

简单的:输出到控制台

复杂的:写入磁盘文件。

记录日志到磁盘文件:

使用basicConfig()的配置函数,更改上面的代码:

logging.basicConfig(filename='example.log',level=logging.DEBUG)

这样,会在当前文件夹下生成一个example.log文件,用于记录日志信息。就是logging.info()输出的信息。

在消息中显示时间/日期

日志很重要的是,可以在之后查看,所以要加上日期时间:

logging.basicConfig(filename='example.log',format="%(levelname)s: %(asctime)s %(message)s",level=logging.INFO) #进行配置

加上参数:format="%(levelname)s: %(asctime)s %(message)s"

会在日志显示:

WARNING: 2019-11-16 19:29:46,496 n= 0

是否要深入学习?

如果日志需求很简单,上面的就足够了,否则可以看进阶日志教程和操作手册。

第四种pdb, Python自带的调试器

$ python -m pdb err.py> /Users/michael/Github/learn-python3/samples/debug/err.py(2)()-> s = '0'

带上参数-m pdb

运行时,c是continue下一个块, n是next即下一行,q是退出。

如果想要设置一个中断点,在代码中加上pdb.set_trace()方法即可,运行是到这行代码会暂停并进入调试程序。

⚠️类似Ruby/Rails的byebug。中断点是byebug, 启动脚本: byebug xxx.rb

IDE: 集成开发环境

如果要比较爽地设置断点、单步执行,就需要一个支持调试功能的IDE。目前比较好的Python IDE有:

Visual Studio Code:https://code.visualstudio.com/,需要安装Python插件。

另外,Eclipse加上pydev插件也可以调试Python程序。

虽然用IDE调试起来比较方便,但是最后你会发现,logging才是终极武器。

文件的定位读写

f = open("123.txt", "w+")

f.write("hello world")

content = f.read()

print(content) # 为什么打印不出内容?

这是因为有一个关于打印指针的概念。

第3行的变量content其实是""空字符串,因为文件中的指针当前指向的是文本的最后。

所以,如果希望打印第2行输入的字符,需要调整文件指针的位置。这里涉及2个方法:

tell(),判断当前指针的位置

seek(offset, from) 移动指针

seek(offset, from)有2个参数

offset:偏移量。正整数向右偏移,负数向左偏移。

from:方向

0:表示文件开头

1:表示指针当前的位置

2:表示文件末尾

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值