Python学习目录python
在程序运行过程当中,总会遇到各类各样的错误,Python内置了一套异常处理机制,来帮助咱们进行错误处理。编程
在程序运行的过程当中,若是发生了错误,能够事先约定返回一个错误代码,这样,就能够知道是否有错,以及出错的缘由。在操做系统提供的调用中,返回错误码很是常见。好比打开文件的函数open()
,成功时返回文件描述符(就是一个整数),出错时返回-1
。网络
用错误码来表示是否出错十分不便,由于函数自己应该返回的正常结果和错误码混在一块儿,形成调用者必须用大量的代码来判断是否出错,因此高级语言一般都内置了一套try...except...finally...
的错误处理机制,Python也不例外。eclipse
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
语句块,至此,执行完毕。函数式编程
Python的错误其实也是class,全部的错误类型都继承自BaseException
,因此在使用except
时须要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。函数
若是错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,而后程序退出。来看看err.py
:工具
# err.py:
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
bar('0')
main()
复制代码
执行,结果以下:post
$ 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
复制代码
咱们从上往下能够看到整个错误的调用函数链。单元测试
若是不捕获错误,天然可让Python解释器来打印出错误堆栈,但程序也被结束了。既然咱们能捕获错误,就能够把错误堆栈打印出来,而后分析错误缘由,同时,让程序继续执行下去。学习
Python内置的logging
模块能够很是容易地记录错误信息:
# err_logging.py
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')
复制代码
执行上述模块:
$ python3 err_logging.py
ERROR:root:division by zero
Traceback (most recent call last):
File "err_logging.py", line 13, in main
bar('0')
File "err_logging.py", line 9, in bar
return foo(s) * 2
File "err_logging.py", line 6, in foo
return 10 / int(s)
ZeroDivisionError: division by zero
END
复制代码
由于错误是class,捕获一个错误就是捕获到该class的一个实例。所以,错误并非凭空产生的,而是有意建立并抛出的。Python的内置函数会抛出不少类型的错误,咱们本身编写的函数也能够抛出错误。
若是要抛出错误,首先根据须要,能够定义一个错误的class,选择好继承关系,而后,用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('0')
复制代码
执行,能够最后跟踪到咱们本身定义的错误:
$ python3 err_raise.py
Traceback (most recent call last):
File "err_throw.py", line 11, in <module>
foo('0')
File "err_throw.py", line 8, in foo
raise FooError('invalid value: %s' % s)
__main__.FooError: invalid value: 0
复制代码
最后,咱们来看另外一种错误处理的方式:
# err_reraise.py
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()
复制代码
在bar()
函数中,咱们明明已经捕获了错误,可是,打印一个ValueError!
后,又把错误经过raise
语句抛出去了,这不有病么?
其实这种错误处理方式不但没病,并且至关常见。捕获错误目的只是记录一下,便于后续追踪。可是,因为当前函数不知道应该怎么处理该错误,因此,最恰当的方式是继续往上抛,让顶层调用者去处理。比如一个员工处理不了一个问题时,就把问题抛给他的老板,若是他的老板也处理不了,就一直往上抛,最终会抛给CEO去处理。
raise
语句若是不带参数,就会把当前错误原样抛出。此外,在except
中raise
一个Error,还能够把一种类型的错误转化成另外一种类型:
try:
10 / 0
except ZeroDivisionError:
raise ValueError('input error!')
复制代码
程序能一次写完并正常运行的几率很小,基本不超过1%。总会有各类各样的bug须要修正。有的bug很简单,看看错误信息就知道,有的bug很复杂,咱们须要知道出错时,哪些变量的值是正确的,哪些变量的值是错误的,所以,须要一整套调试程序的手段来修复bug。
用print()
把可能有问题的变量打印出来看看。
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('0')
复制代码
assert
的意思是,表达式n != 0
应该是True
,不然,根据程序运行的逻辑,后面的代码确定会出错。
若是断言失败,assert
语句自己就会抛出AssertionError
。
logging容许你指定记录信息的级别,有debug
,info
,warning
,error
等几个级别,当咱们指定level=INFO
时,logging.debug
就不起做用了。同理,指定level=WARNING
后,debug
和info
就不起做用了。这样一来,你能够放心地输出不一样级别的信息,也不用删除,最后统一控制输出哪一个级别的信息。
logging
的另外一个好处是经过简单的配置,一条语句能够同时输出到不一样的地方,好比console和文件。
import logging
logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
复制代码
Python的调试器pdb,让程序以单步方式运行,能够随时查看运行状态。咱们先准备好程序:
# err.py
s = '0'
n = int(s)
print(10 / n)
复制代码
而后启动:
$ python -m pdb err.py
> /Users/michael/Github/learn-python3/samples/debug/err.py(2)<module>()
-> s = '0'
复制代码
以参数-m pdb
启动后,pdb定位到下一步要执行的代码-> s = '0'
。输入命令l
来查看代码:
(Pdb) l
1 # err.py
2 -> s = '0'
3 n = int(s)
4 print(10 / n)
复制代码
输入命令n
能够单步执行代码。
这个方法也是用pdb,可是不须要单步执行,咱们只须要import pdb
,而后,在可能出错的地方放一个pdb.set_trace()
,就能够设置一个断点:
# err.py
import pdb
s = '0'
n = int(s)
pdb.set_trace() # 运行到这里会自动暂停
print(10 / n)
复制代码
运行代码,程序会自动在pdb.set_trace()
暂停并进入pdb调试环境,能够用命令p
查看变量,或者用命令c
继续运行。
目前比较好的Python IDE有:
isual Studio Code:code.visualstudio.com/,须要安装Python插件。
PyCharm:www.jetbrains.com/pycharm/
另外,Eclipse加上pydev插件也能够调试Python程序。
单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工做。
若是你常常阅读Python的官方文档,能够看到不少文档都有示例代码。
能够把这些示例代码在Python的交互式环境下输入并执行,结果与文档中的示例代码显示的一致。
这些代码与其余说明能够写在注释中,而后,由一些工具来自动生成文档。