九、错误异常处理
在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因。在操作系统提供的调用中,返回错误码非常常见。比如打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1。
python内置了一套try…except…finally…的错误处理机制
try:
x = 5/0
print(x)
except ZeroDivisionError as e: #捕获异常错误消息
print('',e)
except: #不知道什么异常可以不加异常名
print('其他')
else:
print('没有异常')
finally: #不管有没有异常都会运行
pass
当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。如果没有错误,则执行else,如果不知道错误类型,则可以在except后面什么都不写。
raise AttributeError('属性错误') #抛出异常
#如果一个代码未来要写
def method():
raise NotImplementedError('完成代码')
可以通过rasie主动报错。
如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。
Python内置的logging模块可以非常容易地记录错误信息:
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')
同样是出错,但程序打印完错误信息后会继续执行,并正常退出:
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
十、测试
为了编写单元测试,我们需要引入Python自带的unittest模块,单元测试:
- 对代码最基本单元(函数、方法)的测试
- 给予特定条件判断结果是否复合预期
- 相对整个程序的测试,单元测试简化了测试任务
- unittest 模块
import unittest
def add(a, b):
return a + b
def subtract(a, b):
return a - b
class MyTest(unittest.TestCase):
def test_aa(self):
self.assertEqual(8, add(5, 3))
def test_subtract(self):
self.assertEqual(2, subtract(5, 3))
if __name__ == '__main__':
unittest.main()
- 测试用例继承自unittest
- test_定义功能测试函数名(一个函数里只能顶一个测试项)
- setUp()函数定义装备初始化代码
- tearDown()函数执行清理工作
'''计算器代码块'''
class Calculator:
def __init__(self, x, y):
self.x = x
self.y = y
def add(self):
return self.x + self.y
def substract(self):
return self.x - self.y
if __name__ == '__main__':
pass
‘’‘测试代码块'''
import unittest
import sys
print(sys.path)
from t18_1 import Calculator # 在D:\\Project\\python\\test1的python下时可以导入的
class CalculatorTest(unittest.TestCase):
def setUp(self):
self.c = Calculator(5, 3) #节省了代码
def test_add(self):
# c = Calculator(5,3)
self.assertEqual(8, self.c.add())
def test_substract(self):
# c = Calculator(5,3)
self.assertEqual(2, self.c.substract())
# 一般断开数据库连接,打开的文件关闭
def tearDown(self):
del self.c
if __name__ == '__main__':
unittest.main()
常用的断言方法如下:
assertEqual(值,表达式) | 是否相等 |
---|---|
assertTrue(值,表达式) | 是否为真 |
assertIn(值,表达式) | 是否有 |
assertAlmostEqual(值,表达式) | 是否约等于 |
assertIs(值,表达式) | 是否同一个引用 |
assertNone(表达式) | 是否为空 |
assertIsInstance(值,表达式) | 是否为某个类型 |
assertGreaterEqual/assertGreater/assertNotEqual() | 是否大于等于/大于/不等于 |
person = {'name': 'Mike', 'age': 20}
numbers = [1, 3, 2, 88, 7, 44]
s = '优品课堂 codeclassroom.com'
class TestAssert(unittest.TestCase):
def test_assert_method(self): # 一个函数里面只能测试一个,多了识别不出来
self.assertEqual('Mike',person.get('name'))
self.assertTrue('优品课堂' in s)
self.assertIn('优品课堂',s)
self.assertAlmostEqual(3.3 1.1+2.2)
self.asserIs(True+1,2)
self.asserIsNone(person.get('Name',None))
self.assertIsInstance(numbers[0],int)
self.assertGreater(7, numbers[0])
十一、数值与日期
格式话和小数位处理:
>>> a=520
>>> b=1234567890.123456
>>> '数值:{}'.format(a)
'数值:520'
>>> '数值:{}'.format(b)
'数值:1234567890.123456'
>>> f'数值:{a}'
'数值:520'
>>> f'数值:{b}'
'数值:1234567890.123456'
>>> '数值:{:f}'.format(a)
'数值:520.000000'
>>> f'数值:{a:f}'
'数值:520.000000'
>>> f'数值:{a:+f}'
'数值:+520.000000'
>>> f'数值:{b:.2f}'
'数值:1234567890.12'
>>> f'数值:{b:.4f}'
'数值:1234567890.1235'
>>> '{:.2f}'.format(5/3)
'1.67'
>>> import math
>>> math.trunc(b) #向零取整
1234567890
>>> math.floor(b) #向下取整
1234567890
>>> math.ceil(b) #向上取整
1234567891
>>> round(b,4) #四舍五入
1234567890.1235
>>> round(12.57,1)
12.6
随机数:
>>> import random
>>> lst = list(range(1,11))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> random.choice(lst)
7
>>> random.choice(lst)
8
>>> random.choice(lst)
3
>>> random.sample(lst,3)
[6, 7, 4]
>>> random.sample(lst,3)
[4, 8, 5]
>>> random.shuffle(lst)
>>> lst
[4, 8, 9, 6, 2, 3, 5, 1, 10, 7]
>>> random.shuffle(lst)
>>> lst
[6, 1, 4, 3, 10, 9, 8, 7, 2, 5]
>>> random.random()
0.3133028470308882
>>> random.random()
0.9506817283904866
>>> random.random()
0.5840614913876016
>>> random.random()
0.4775922849600309
>>> random.randint(1,10) #包括最后一个数
2
>>> random.randint(1,10)
7
>>> random.randint(1,10)
10
>>> random.getrandbits(5) #生成一个指定比特位的随机数
2
>>>
时间和日期
>>> import datetime
>>> datetime.MAXYEAR
9999
>>> datetime.MINYEAR
1
>>> today = datetime.date.today()
>>> today
datetime.date(2019, 9, 24)
>>> today.year
2019
>>> today.month
9
>>> today.day
24
>>> today.weekday() #会-1
1
>>> today.isoweekday() #符合实际
2
>>> birthdate = datetime.date(2019,9,1)
>>> birthdate.year
2019
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2019, 9, 24, 0, 29, 43, 749136)
>>> now.second
43
>>> now.microsecond
749136
>>>
字符串到日期时间 datetime.datetime.strptime(str,'格式‘),日期时间到字符串 datetime.datetime.strftime(‘格式’).
%Y 四位的年分、%y 两位的年份、%m 二位月两、%d 两位日期、%H 两位的小时、%M 两位的分钟、%S 两位的秒、%f 微妙、%w 星期数0,1,…
>>> import datetime
>>> s = '2019-9-24'
>>> type(s)
<class 'str'>
>>> t = datetime.datetime.strptime(s,'%Y-%m-%d')
>>> t
datetime.datetime(2019, 9, 24, 0, 0)
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2019, 9, 24, 0, 33, 26, 407715)
txt = now.strftime('%Y/%m/%d')
>>> txt
'2019/09/24'
时间差:
>>> d= datetime.datetime(2018,3,5,22,44)
>>> birthdate = datetime.datetime(2016,5,2,19,33,44)
>>> d - birthdate
datetime.timedelta(672, 11416) #天数,秒
>>> diff = d - birthdate
> diff.days
672
>>> diff.seconds
11416
>>> diff.total_seconds()
58072216.0
>>> o = datetime.datetime(2008,8,8,20,8)
> o+datetime.timedelta(days=100)
datetime.datetime(2008, 11, 16, 20, 8)
>>> d
datetime.datetime(2018, 3, 5, 22, 44)
>>> result = d+datetime.timedelta(days=-100)
>>> result
datetime.datetime(2017, 11, 25, 22, 44)
d +datetime.timedelta(seconds=3000)
datetime.datetime(2018, 3, 5, 23, 34)
>>> result.hour
22
>>> from datetime import date,time,datetime,timedelta
注意,date是日期,time是时间,datetime是时间加日期,内部的方法基本一致。