2020-08-15

python_learning_03

错误、调试和测试
我认为学习编程,肯定要调试,调试就有可能发现自己写的程序无法运行,错误分为语法错误和逻辑错误,语法错误大多数编译器是能察觉的,要找语法错误,就从编译器给出的位置上下寻找,找出错误,每种语言都有它的写法规则,出现语法错误,就是不符合语法规则。
我认为相比语法错误,逻辑错误要难找,编译器大多不能识别逻辑错误。逻辑错误是用正确的语法写的正确的语句,却不符合前后的逻辑。如果编译器没报错,但是仍然无法运行,就是逻辑错误了。逻辑错误需要从一句开始看,我觉得还是比较花费时间的。
在python中学习中,如果发生错误,可是事先约定一个错误代码,这样就可以知道,
用错误码来表示是否出错十分不便,因为函数本身应该返回的正常结果和错误码混在一起,造成调用者必须用大量的代码来判断是否出错:
python有自己的调试函数
def foo():
r = some_function()
if r==(-1):
return (-1)
# do something
return r

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

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

try
让我们用一个例子来看看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
从输出可以看到,当错误发生时,后续语句print(‘result:’, r)不会被执行,except由于捕获到ZeroDivisionError,因此被执行。最后,finally语句被执行。然后,程序继续按照流程往下走。

如果把除数0改成2,则执行结果如下:

try…
result: 5
finally…
END
由于没有错误发生,所以except语句块不会被执行,但是finally如果有,则一定会被执行(可以没有finally语句)。

可以有多个except来捕获不同类型的错误:

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’)
int()函数可能会抛出ValueError,所以我们用一个except捕获ValueError,用另一个except捕获ZeroDivisionError。

此外,如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:

try:
print(‘try…’)
r = 10 / int(‘2’)
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’)
Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。比如:

try:
foo()
except ValueError as e:
print(‘ValueError’)
except UnicodeError as e:
print(‘UnicodeError’)
调试
第一种方法简单直接粗暴有效,就是用print()把可能有问题的变量打印出来看看:

def foo(s):
n = int(s)
print(’>>> n = %d’ % n)
return 10 / n

def main():
foo(‘0’)

main()
执行后在输出中查找打印的变量值:

$ python err.py

n = 0
Traceback (most recent call last):

ZeroDivisionError: integer division or modulo by zero

单元测试
如果你听说过“测试驱动开发”(TDD:Test-Driven Development),单元测试就不陌生。

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

比如对函数abs(),我们可以编写出以下几个测试用例:

输入正数,比如1、1.2、0.99,期待返回值与输入相同;

输入负数,比如-1、-1.2、-0.99,期待返回值与输入相反;

输入0,期待返回0;

输入非数值类型,比如None、[]、{},期待抛出TypeError。

文档读写
文档读写我感觉有点像C语言
读文件
要以读文件的模式打开一个文件对象,使用Python内置的open()函数,传入文件名和标示符:

f = open(’/Users/michael/test.txt’, ‘r’)
标示符’r’表示读,这样,我们就成功地打开了一个文件。

如果文件不存在,open()函数就会抛出一个IOError的错误,并且给出错误码和详细的信息告诉你文件不存在:

f=open(’/Users/michael/notfound.txt’, ‘r’)
Traceback (most recent call last):
File “”, line 1, in
FileNotFoundError: [Errno 2] No such file or directory: ‘/Users/michael/notfound.txt’

StringIO
很多时候,数据读写不一定是文件,也可以在内存中读写。

StringIO顾名思义就是在内存中读写str。

要把str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可:

from io import StringIO
f = StringIO()
f.write(‘hello’)
5

f.write(’ ')
1

f.write(‘world!’)
6

print(f.getvalue())
hello world!
打开Python交互式命令行,我们来看看如何使用os模块的基本功能:

import os
os.name # 操作系统类型
‘posix’
如果是posix,说明系统是Linux、Unix或Mac OS X,如果是nt,就是Windows系统。

要获取详细的系统信息,可以调用uname()函数:
注意uname()函数在Windows上不提供,也就是说,os模块的某些函数是跟操作系统相关的。
进程和线程
Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程:

import os

print(‘Process (%s) start…’ % os.getpid())

Only works on Unix/Linux/Mac:

pid = os.fork()
if pid == 0:
print(‘I am child process (%s) and my parent is %s.’ % (os.getpid(), os.getppid()))
else:
print(‘I (%s) just created a child process (%s).’ % (os.getpid(), pid))
运行结果如下:

Process (876) start…
I (876) just created a child process (877).
I am child process (877) and my parent is 876.

启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行:

import time, threading

新线程执行的代码:

def loop():
print(‘thread %s is running…’ % threading.current_thread().name)
n = 0
while n < 5:
n = n + 1
print(‘thread %s >>> %s’ % (threading.current_thread().name, n))
time.sleep(1)
print(‘thread %s ended.’ % threading.current_thread().name)

print(‘thread %s is running…’ % threading.current_thread().name)
t = threading.Thread(target=loop, name=‘LoopThread’)
t.start()
t.join()
print(‘thread %s ended.’ % threading.current_thread().name)
执行结果如下:

thread MainThread is running…
thread LoopThread is running…
thread LoopThread >>> 1
thread LoopThread >>> 2
thread LoopThread >>> 3
thread LoopThread >>> 4
thread LoopThread >>> 5
thread LoopThread ended.
thread MainThread ended.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值