您的位置:首页 > 编程语言 > Python开发

python 学习笔记 错误调试 文件读写

2015-01-27 18:34 686 查看
九:错误,调试和测试:
1:错误处理:
在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样就知道是否有错,以及出错的原因。Python内置 try....except.....finally.....的错误处理机制

try:
print 'try...'
r=10/0
print 'result'
except ZeroDivisionError,e:
print 'except:',e
finally:
print 'finally....'
print 'END'
输出结果:
try....
except:integer division or modulo by zero
finally...
END

和java一样 可以用多个except 来捕捉不同类型的错误,如果没有错误发生,可以再except语句块后面加上一个else 当没有错误发生的时候会自动执行else语句
Python的错误 其实也是class 所有的错误类型都继承自BaseException 所以在使用except时需要注意 它不但捕捉这个类型的错误还会把子类也一网打尽。
try:
foo()
except StandardError,e:
print 'standartError'
except ValueError,e:
print 'ValueError'
由于ValueError是StandardError的子类 所以except永远也捕捉不到ValueError。
如果错误没有被捕捉 他将会一直往上抛,最后被Python解释器捕获 打印错误信息。
Python内置的logging模块 可以非常容易的记录错误的错误信息:
#err.py
import logging

def foo(s):
return 10/int(s)

def bar(s):
return foo(s)*2

def main():
try:
bar('0')
except StandardError,e:
logging.exception(e)

main()
print 'End'
通过对logging的配置 还可以将错误记录打印到日志文件中。

抛出错误:
因为错误是一个class 所以捕获错误就是到改class的一个实例,因此错误是可以有意创建并且抛出的。如果要抛出错误,首先根据需要,可以定义一个错误的class选择好继承关系 然后用raise语句抛出一个错误的实例
#err.py
class FooError(StandardError):
pass

def foo(s):
n=int(s)
if n==0:
raise FooError('invalid value:%s' % s)
return 10/n
只有在必要的时候才定义自己的错误类型 如果可以选择Python已有的内置错误类型 尽量使用Python内置错误类型。
raise语句如果不带参数 就会把当前错误原样的抛出,except和raise一个error 还可以把一种类型的错误转换成另一种类型的错误。 只要是合理的逻辑都可以。

2:调试:
1:print
2:断言 assert 凡是用print来辅助查看的地方都可以用断言来代替
#err.py
def foo(s)
n=int(s)
assert n!=0,'no is zero!'
return 10/n

def main():
foo('0')
assert 的意思是 表达式n!=0应该是True 否则后面的代码就会出错 如果断言失败 assert 语句本身就会抛出AssertionError 启动Python解释器的时候可以用 -0参数关闭assert
3:logging 把print替换成logging 和assert比 logging不会抛出错误 而且还可以输出到文件
#err.py
import logging

s='0'
n=int(s)
logging,info('n=%d' %n)
print 10/n
logging可以 输出一段文本 运行 发现除了ZeroDivisionError 没有任何的信息 这需要在 import logging 后面添加一行配置
import logging
logging.basicConfig(level=logging.INFO)
4:pdb Python的调试器 让程序以单步方式运行,可以随时的查看运行状态。
Python -m pdb err.py
l 查看当前代码
n 单步执行代码
p 变量名 查看变量
q 结束调试 退出程序
5:pdb.set_trace()
这个方法也是pdb 但是不需要单步执行 只需要import pdb 然后在有可能出错的地方放一个pdb.set_trace() 就可以设置一个断点 运行代码 程序会自动的在pdb.set_trace()暂停 并进入到pdb的调试环境中
可以使用p查看变量或者 使用c继续运行。

3:单元测试:
单元测试时用来对一个模块,一个函数,或者一个类 进行正确性检验的测试工作。
比如 对于函数abs() 我们可以编写出一下几个测试用例:
1: 输入正数 比如1 ,1.2 0.99 期待返回值与输入相同;
2:输入负数 比如 -1 -1.2 -0.99 期待返回值与输入想法;
3:输入0 期待返回0
4:输入非数值类型 比如 None,【】,{} 期待抛出 TypeError
把上面的测试用例 放到一个测试模块中 这就是一个完整的单元测试。
如果单元测试通过 说明我们 这个函数能够正常工作,如果单元测试不通过 要么bug 要么测试条件输入不正确。
编写一个Dict类 这个类的行为和dict一致 但是可以通过属性来访问 用起来就像:
>>>d=Dict(a=1,b=2)
>>>d['a']
1
>>>d.b
2
mydict.py:
class Dict(dict):
def __init__(self,**kw):
super(Dict,self).__init__(**kw)

def __getattr__(self,key):
try:
return self[key]
except:
raise AttributeError(r'' 'Dict'object has no attribute '%s' '' % key)

def __setattr__(self,key,value)
self[key]=value
单元测试:
import unittest

from mydict import Dict

class TestDict(unittest.TestCase):

def test_init(self):
d=Dict(a=1,b='test')
self.assertEquals(d.a,1)
self.assertEquals(d.b,'test')
self.assertTrue(isinstance(d,dict))

def test_key(self):
d=Dict()
d['key']='value'
self.assertEquals(d.key,'value')

def test_attr(self):
d=Dict()
d.key='value'
self.assertTrue('key' in d)
self.assertEquals(d['key'],'value')

def test_keyerror(self):
d=Dict()
with self.assertRaise(keyError):
value=d['empty']

def test_attrerror(self):
d=Dict()
with self.assertRaises(AttributeError):
value=d.empty
编写单元测试 就是自己写一个测试类 然后从unittest.TestCase继承
以test开头的方法都是测试方法 不易test开头的方法不被认为是测试方法 测试的时候不会被执行
对于每一类测试都要编写一个test_xxx方法 最常用断言来判断
最后两种断言是 期待抛出指定的error
运行测试单元:
1:在mydict_test.py 的最后两行加上:
if __name__=='__main__':
unittest.main()
2:python -m unittest mydict_test
可以再单元测试中编写两个特殊的setUp()和tearDown()方法 这两个方法分别在每调用一个测试方法的前后被执行。

4:文档测试:
Python的文档注释模块可以直接提取注释中的代码并进行测试
doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确 只有在测试异常的时候 可以用...表示中间一大段烦人的输出
用doctest 来测试Dict
class Dict(dict):
...
simple dict but alse support access as x.y style.

>>>d1=Dict()
>>>d1['x']=100
>>>d1.x
100
>>>d1.y=200
>>>d1['y']
200
>>>d2=Dict(a=1,b=2,c='3')
>>>d2.c
'3'
>>>d2['empty']
Tracebace...
>>>d2.empty
Traceback...

def __init__(self,**kw):
super(Dict,self).__init__(**kw)

def __getattr__(self,key):
try:
return self[key]
except:
raise AttributeError(r'' 'Dict'object has no attribute '%s' '' % key)

def __setattr__(self,key,value)
self[key]=value
if __name__=='__main__':
import doctest
doctest.testmod() ..

十 IO编程:(同步IO 和异步IO)
1: 文件读写:
在磁盘上读写文件都是有操作系统提供的 现代操作系统不允许普通的程序 直接操作磁盘
>>>f=open('/Users/michael/test.txt','r')
Python内置的open()函数 传入文件名和提示符 标示符r表示读 这样我们就成功的打开了一个文件
如果文件不存在 open函数就会抛出一个IOError的错误 并给出错误码和详细信息
如果文件打开成功 接下来就可以调用read()方法 可以一次的读取文件的全部内容 Python把内容读到内存 用一个str对象表示
>>>f.read()
'Hello,world'
最后一步 是调用close()方法关闭文件 文件使用完毕后必须关闭 因为文件对象会占用操作系统的资源 并且操作系统同一时间能够打开的文件数量是有限的
>>>f.close()
try:
f=open('D:/a.txt','r')
print f.read()
finally:
if f:
f.close()
可以简化为:
with open('D:/a.txt','r') as f:
print f.read()
调用一次f.read()将会一次性读取文件的全部内容,保险起见 可以反复调用read(size)方法 每次最多读取size个字节的内容 另外 调用readlines() 可以每次读取一行的内容
如果文件很小 read()一次性读取最方便 不确定文件大小 read(size)最保险 如果是配置文件 readlines()最方便
for line in f.readlines():
print(line.strip()) #把末尾的'\n'去掉

2:file-like Object
像open()函数返回的这种有个read()方法的对象 在Python中统称为file_like Object 除了file外 还可以是内存的字节流 网络流 自定义流 等等 file-like Object 不要求从定义类继承
只要写个read()方法就行
StringIO 就是在内存中创建的file_like Object 常用作临时缓冲
要读取二进制文件 需要使用 ‘rb’模式打开文件即可
要读非ASCII编码的文本文件就必须以二进制模式打开 在解码 比如GBK编码的文件:
>>>f=open('/Users/lc/gbk.txt','rb')
>>>u=f.read().decode('gbk')
>>>print u
python 提供了一个codecs模块帮我们在读文件时自动转换编码 直接读出Unicode
import codecs
with codecs.open('/User/lc/test.txt','r','gbk') as f:
f.read()
写文件 写文件和读文件时一样的 唯一的区别就是调用的时候 传入的标示符是 ‘w’‘wb’标示读写文本文件和二进制文件
>>>f.open('/Users/lc/test.txt','w')
>>>f.write('Hello,World!')
>>>f.close()
或者使用with 语句
with open('Users/lc/test.txt','w') as f:
f.write('Hello world!')
使用with语句操作文件的IO是一个好习惯

2:操作文件和目录
>>>import os
>>>os.name
可以获取系统的名字信息 如果是nt 表示windows 如果是POSIX表示的是Linux
>>>os.uname()
函数可以获取系统的详细信息 但是windows不支持。
环境变量
操作系统定义的环境变量 全部保存在 os.environ dict 要获取某个环境变量的值可以调用 os.getenv('变量名')函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: