摘录: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. Linux三种SSH协议登陆方式

    在实际工作中遇到了三种不同SSH协议登陆Linux服务器的方式,由简单到复杂分别阐述:一.最简单也是最不安全的root账号密码登陆通过root账号+root密码登陆Linux服务器. 二.普通用户登陆 ...

  2. 【VS开发】关于在CFormView中实现CListCtrl控件的注意事项

    [VS开发]关于在CFormView中实现CListCtrl控件的注意事项 标签(空格分隔): [VS开发] 今天调试中发现了一项非常令人恼怒的事情,本来早都知道在CFormView中没有了像在对话框 ...

  3. FTL-SLC&MTC&TLC

    1.博客 SLC.. http://diybbs.zol.com.cn/67/231_661182.html 2.FTL --作者在普及了一些FTL基本知识后,主要分析了在linux上实现的途径 ht ...

  4. Ubuntu更换科大源

    更换科大源 方案一:在命令行输入 sudo gedit /etc/apt/sources.list ,打开系统自带源文件. 将文件内源删除,更换为以下科大源: deb http://mirrors.a ...

  5. 第一章 impala的安装

    目录 第一章 impala的安装 1.impala的介绍 imala基本介绍 impala与hive的关系 impala的优点 impala的缺点: impala的架构以及查询计划 2.impala的 ...

  6. java水题集

    POJ - 1220 进制转换 import java.io.*; import java.util.*; import java.math.*; public class Main { public ...

  7. 【一个蒟蒻的挣扎】最小生成树—Kruskal算法

    济南集训第五天的东西,这篇可能有点讲不明白提前抱歉(我把笔记忘到别的地方了 最小生成树 概念:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的 ...

  8. python 文件写入

    def write_file(): """ 文件写入""" file_name = "wri2te_test.txt" ...

  9. Stardew Valley(星露谷物语)Mod开发之路 1环境配置

    首先来说明一下,我写这个章节本身也是对学习过程的记录,主要参考了http://canimod.com/guides/creating-a-smapi-mod中的内容.也推荐大家看看. *这些是我的开发 ...

  10. mvc验证码图片生成

    /// <summary> ///生成验证码 /// </summary> public class VerifyCode { /// <summary> /// ...