摘录:https://www.liaoxuefeng.com/wiki/1016959663602400/1017598873256736

  • 错误处理
  • 调试
  • 新增:2020-01-19 增加关于文件读取的方法tell(), seek()等知识。

错误处理

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

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

try

try:
print('try...')
r = 10 / int('')
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')
  • 如果有错误,根据发生不同类型的错误,使用不同的except处理。

    • int('a')会出发 ValueError
    • 10/0会触发ZeroDivisionError。
    • 如果没有找到expect匹配的异常,则将异常传递到外部的try语句中。会显示traceback
  • 否则代表没有错误,则执行else。
  • 无论是否发生异常,最后都要执行finally

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

看文档Built-in Exceptions

https://docs.python.org/3/library/exceptions.html#exception-hierarchy

try的好处

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

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

def foo(s):
return 10 / int(s) def bar(s):
return foo(s) * 2 def main():
try:
bar('')
except Exception as e:
print('Error:', e)
finally:
print('finally...')

调用栈

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

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

例子:

import sys

try:
f = open('example.log', 'r+')
s = f.readline()
i = int(s.stripd())
except OSError as err:
print("OS error: {}".format(err))
except ValueError:
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 <class 'AttributeError'>
Traceback (most recent call last):
File "linshi.py", line 6, in <module>
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,查看错误。

例子:

def this_fails():
x = 1/0 try:
this_fails()
except ZeroDivisionError 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

import logging

def foo(s):
return 10 / int(s) def bar(s):
return foo(s) * 2 def main():
try:
bar('')
except Exception as e:
logging.exception(e) main()
print('END')

抛出异常 raise语句

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

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

# err_raise.py
class FooError(ValueError):
pass def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n foo('')
  • 编写一个错误类FooError。
  • 用raise语句,生成FooError的实例。

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

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

目的:

  • 用except捕获指定❌
  • 然后,用raise语句进行trackback。

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

from functools import reduce

def str2num(s):
return int(s) #改为float(s)即可纠正错误 def calc(exp):
ss = exp.split('+')
ns = map(str2num, ss)
return reduce(lambda acc, x: acc + x, ns) #functools的方法reduce(function, iterable) def main():
try:
r = calc('99 + 88 + 7.6')
print('99 + 88 + 7.6 =', r)
except ValueError as e:
print(">>>%s" % e)
# raise
main()
  • 加上单独的raise的作用,就是把当前错误原样抛出,可进行后续的追踪。
  • 由于当前函数不知道应该怎么处理该错误,所以,继续往上抛错误,让顶层调用者去处理。
  • 如果raise带了不同的异常类实例的参数,,可以把一种类型的错误转化为另一种类型:
try:
10 / 0
except ZeroDivisionError:
raise ValueError('input error!')

finally的作用

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

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


调试

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

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

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

#err.py
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n def main():
foo('')
main()
$ python -O err.py

注意是大写的字母O,

第三种logging。

import logging
logging.basicConfig(level=logging.INFO) #进行配置,logging级别,默认是WARNING,所以INFO,DEBUG级别的不会被追踪 s = ''
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)<module>()
-> s = ''

带上参数-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插件。

PyCharm:http://www.jetbrains.com/pycharm/

另外,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:表示文件末尾

python: 错误处理try详解 ,traceback调用栈, 调试(logging)的更多相关文章

  1. 详解JavaScript调用栈、尾递归和手动优化

    调用栈(Call Stack) 调用栈(Call Stack)是一个基本的计算机概念,这里引入一个概念:栈帧. 栈帧是指为一个函数调用单独分配的那部分栈空间. 当运行的程序从当前函数调用另外一个函数时 ...

  2. python错误处理—try…catch…finally、调用栈分析

    高级语言包括python一般都内置了一套try…catch…finally的错误处理机制: >>> try: ... print('try...') ... r = 10 / 0 . ...

  3. Python数据类型及其方法详解

    Python数据类型及其方法详解 我们在学习编程语言的时候,都会遇到数据类型,这种看着很基础也不显眼的东西,却是很重要,本文介绍了python的数据类型,并就每种数据类型的方法作出了详细的描述,可供知 ...

  4. Python中time模块详解

    Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...

  5. python的requests用法详解

    Requests是一个Python语言写的http相关设置或者请求的一个库 安装:pip install Requests或者pip3 install requests 使用的时候要import re ...

  6. python基础之函数详解

    Python基础之函数详解 目录 Python基础之函数详解 一.函数的定义 二.函数的调用 三.函数返回值 四.函数的参数 4.1 位置参数 4.2 关键字参数 实参:位置实参和关键字参数的混合使用 ...

  7. python之OS模块详解

    python之OS模块详解 ^_^,步入第二个模块世界----->OS 常见函数列表 os.sep:取代操作系统特定的路径分隔符 os.name:指示你正在使用的工作平台.比如对于Windows ...

  8. python之sys模块详解

    python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...

  9. 【转载】详解CreateProcess调用内核创建进程的过程

    原文:详解CreateProcess调用内核创建进程的过程 昨天同学接到了腾讯的电面,有一题问到了CreateProcess创建进程的具体实现过程,他答得不怎么好吧应该是, 为了以防万一,也为了深入学 ...

随机推荐

  1. 【JAVA开发】eclipse最新版本Eclipse Neon

    这个版本的IDE支持Java.JavaScript.C/C++.PHP和Fortran等多种编程语言: 这个版本首次鼓励用户使用Eclipse Installer来做安装,这是一种由Eclipse O ...

  2. teach-es6-2(class)

    1 属性的简洁表示法 ES6 允许直接写入变量和函数,作为对象的属性和方法.这样的书写更加简洁. var foo = 'bar'; var baz = {foo}; baz // {foo: &quo ...

  3. 简单的搭载Spring cloud框架

    大家不懂的可以在评论区给我留言

  4. Minimum Number of Arrows to Burst Balloons

    There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided ...

  5. Python特色数据类型--列表

    #list[起始索引:终止索引(不包含):步长间隔] list1[5:8] #步长省略则默认为1 #修改元素列表 #列表是一种可变的数据类型,所以可以修改内容 list1 = [0,1,2,3,4] ...

  6. java如何防止反编译(转)

    出处: java如何防止反编译 一些防止java代码被反编译的方法 综述(写在前面的废话) Java从诞生以来,其基因就是开放精神,也正因此,其可以得到广泛爱好者的支持和奉献,最终很快发展壮大,以至于 ...

  7. Postgresql explain的analyze和buffers选项

    sql查询分析: 原文地址:https://blog.csdn.net/qq_28893679/article/details/78316283

  8. Python验证数据的抽样分布类型

    假如要对一份统计数据进行分析,一般其来源来自于社会调研/普查,所以数据不是总体而是一定程度的抽样.对于抽样数据的分析,就可以结合上篇统计量及其抽样分布的内容,判断数据符合哪种分布.使用已知分布特性,可 ...

  9. 搞懂ZooKeeper到底是做啥的

    一.ZooKeeper是啥 ZooKeeper概念 ZooKeeper是一个开源的分布式协调服务(a service for coordinating processes of distributed ...

  10. 【已解决】Field injection is not recommended和Could not autowired. No beans of 'xxx' type found.

    目录 问题 解决办法 备注 问题 在项目中,我们使用Spring的@Autowired注解去引入其他类时有时候阿里的编码规约插件就会提示:"Field injection is not re ...