错误异常处理
在编写代码的过程中,难以避免的出现错误和异常,处理Python的错误或异常是构建稳定程序的重要组成部分。
错误类型
1、语法错误:输入代码时出现错误,如字母错误,标点符号错误,导致语法不正确,比较容易排除。
2、语义错误:语法没问题,但表达的内容不正确,如5/0。这种错误比语法错误处理起来稍加麻烦。
3、逻辑错误:与代码无关,整体程序设计有问题,这种错误最难改正。
当出现语法错误时,运行后会提示:SyntaxError
print('python) #少输入一个’
#运行结果
File "E:/software/pycharm/project/main.py", line 1
print('python)
^
SyntaxError: EOL while scanning string literal
当出现操作异常时,运行后会提示:ZeroDivisionError
a = 5 / 0 #0不能作除数
print(a)
#运行结果
File "E:/software/pycharm/project/main.py", line 1, in <module>
a = 5 / 0
ZeroDivisionError: division by zero
当出现属性异常时,运行后会提示:AttributeError
class Person:
def __init__(self,name):
self.name = name
p = Person('Peter')
print(p.age) #未定义该属性
#运行结果
File "E:/software/pycharm/project/main.py", line 6, in <module>
print(p.age)
AttributeError: 'Person' object has no attribute 'age'
异常处理
异常处理主要针对代码层面的问题,因此主要处理语法错误及语义错误。
使用如下语句处理对应的代码:
1、try:有可能出现的代码。
2、except 异常 as 实例:捕获特定异常。
3、else:未遇异常时执行。
4、finally:不论是否遇到异常均会执行。
5、raise:手动抛出异常。
使用try及except语句可以捕获异常,自定义输出提示。
#正常运行
try:
a = 5 / 2
print(a)
except ZeroDivisionError:
print('不能除零')
else:
print('没有错误')
#运行结果
2.5
没有错误
#除以0
try:
a = 5 / 0
print(a)
except ZeroDivisionError:
print('不能除零')
else:
print('没有错误')
#运行结果
不能除零
class Person:
def __init__(self,name):
self.name = name
p = Person('Peter')
try:
print(p.age) #未定义该属性
except AttributeError as a:
print('遇到属性异常',a)
#运行结果
遇到属性异常 'Person' object has no attribute 'age'
如果在操作文件时遇到异常,需要通过添加finally语句将文件关闭,否则文件将一直处于打开状态。
f = open('data.txt')
try:
f.read()
except:
print('文件操作遇到错误!')
finally:
f.close()
当打算定义一个函数但还没有设计完成时,可以在函数下设置raise语句,提示代码还未完成。
def method():
raise NotImplementedError('该代码还未实现')
method()
#运行结果
Traceback (most recent call last):
File "E:/software/pycharm/project/main.py", line 4, in <module>
method()
File "E:/software/pycharm/project/main.py", line 2, in method
raise NotImplementedError('该代码还未实现')
NotImplementedError: 该代码还未实现
unittest单元测试
unittest单元测试是对代码最基本单元(函数、方法)的测试,给予特定条件判断结果是否符合预期。相对整个程序的测试,单元测试简化了测试任务。
测试代码组织
代码结果正确时:
import unittest #导入unittest模块
def add(a,b): #定义待测试函数
return a + b
class MyTest(unittest.TestCase): #基于unittest.TestCase定义一个测试类
def test_add(self):
self.assertEqual(8,add(5,3)) #利用断言语句判断
if __name__ == '__main__':
unittest.main()
运行结果
代码结果错误时:
import unittest #导入unittest模块
def add(a,b): #定义待测试函数
return a + b
class MyTest(unittest.TestCase): #基于unittest.TestCase定义一个测试类
def test_add(self):
self.assertEqual(8,add(5,4)) #利用断言语句判断
if __name__ == '__main__':
unittest.main()
运行结果
常用断言
1、assertEqual():是否相等。
2、assertTure():是否为真。
3、assertIn():是否包含。
4、assertAlmostEqual():是否约等于。
5、assertIs():是否为同引用。
6、assertIsNone():是否为空。
7、assertIsInstance():是否为某类型实例。
8、assertGreater():是否大于。
······
类与测试装置
我们可以在主程序中定义自己的类与方法,再创建一个测试文件用于测试刚才自己定义的方法,将指定模块导入到测试文件中进行测试。
例,在主程序main.py中定义一个名为Calculator的类,其中包含两个类方法add、subtract。
#main.py
class Calculator:
def __init__(self,x,y):
self.x = x
self.y = y
def add(self):
return self.x + self.y
def subtract(self):
return self.x - self.y
if __name__ == '__main__':
c = Calculator(5,3)
在另一个测试文件test.py中对该类的方法进行测试。
import unittest #导入unittest模块
from main import Calculator #导入主程序中定义的类
class CalculatorTest(unittest.TestCase): #基于unittest.TestCase定义一个测试类
def setUp(self): #将测试中的准备工作放入该方法,如类实例化
self.c = Calculator(5,3)
def test_add(self):
self.assertEqual(8,self.c.add()) #利用断言语句判断方法add
def test_subtract(self):
self.assertEqual(2,self.c.subtract()) #利用断言语句判断方法subtract
def tearDown(self): #测试完成后将数据或链接清除
del self.c
if __name__ == '__main__':
unittest.main()
全部正确时,运行结果如下:
程序错误时
运行结果如下:
数值与日期
数值
格式化
首先定义三个数值
>>> a = 520
>>> b = 1234567890.123456
>>> c = -123456.654321
>>> type(a)
int
>>> type(b)
float
>>> type(c)
float
将数值原样显示出来
>>> '数值:{}'.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'数值:{b:f}'
'数值:1234567890.123456'
>>> f'数值:{b:,f}'
'数值:1,234,567,890.123456'
以百分比格式显示
>>> x = 18
>>> y = 23
>>> '{:.2%}'.format(x / y)
'78.26%'
小数位处理
保留指定的小数位(四舍五入)
>>> f'数值:{b:.2f}'
'数值:1234567890.12'
>>> f'数值:{b:.4f}'
'数值:1234567890.1235'
>>> x = 18
>>> y = 23
>>> '{:.2f}'.format(x / y)
'0.78'
截断小数点后的内容(直接截断,未四舍五入)
>>> import math
>>> math.trunc(123.987)
123
向下取整
>>> math.floor(3.6)
3
>>> math.floor(-2.3)
-3
向上取整
>>> math.ceil(3.6)
4
>>> math.ceil(-2.3)
-2
四舍五入
>>> round(123456.123456,3)
123456.123
>>> round(123456.123456,4)
123456.1235
随机数
生成随机数使用random模块。
随机从一个序列中得到一个值
>>> lst = list(range(1,11))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> import random
>>> random.choice(lst)
9
>>> random.choice(lst)
2
随机从一个序列中得到指定数量的值
>>> random.sample(lst,3)
[8, 2, 6]
>>> random.sample(lst,4)
[9, 5, 4, 6]
将指定序列打乱
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> random.shuffle(lst)
>>> lst
[9, 3, 8, 7, 2, 4, 10, 6, 5, 1]
在某一范围内随机取一个整数
>>> random.randint(1,10)
3
>>> random.randint(1,10)
1
随机取一个大于0小于1的浮点型数值
>>> random.random()
0.7278014028468106
>>> random.random()
0.4930686142921825
随机生成一个指定比特位数的数值
>>> random.getrandbits(5)
28
日趋时间
使用日期与时间需导入datetime模块。
获取日期时间
datetime模块可显示的最大年份与最小年份
>>> import datetime
>>> datetime.MAXYEAR
9999
>>> datetime.MINYEAR
1
获取今天的日期及具体信息
>>> today = datetime.date.today()
>>> today
datetime.date(2020, 2, 15)
>>> today.year
2020
>>> today.month
2
>>> today.day
15
>>> today.weekday() #从0开始计数,今天是周六
5
>>> today.isoweekday() #从1开始计数,按照国际惯例
6
也可以构造一个日期,使用方法和上文的today一样
>>> birthday = datetime.date(2010,2,12)
>>> birthday
datetime.date(2010, 2, 12)
>>> birthday.year
2010
只构造一个时间,不需要日期
>>> t = datetime.time(15,46,32)
>>> t
datetime.time(15, 46, 32)
>>> t.hour
15
>>> t.minute
46
>>> t.second
32
获取当前的日期及时间
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2020, 2, 15, 18, 28, 57, 805300)
>>> now.year
2020
>>> now.hour
18
自己构造一个日期及时间
>>> t = datetime.datetime(1990,3,3,20,33,44)
>>> t
datetime.datetime(1990, 3, 3, 20, 33, 44)
>>> t.month
3
>>> t.minute
33
日期时间与字符串间的转换
字符串转换为时间
>>> s = '2018-3-15'
>>> type(s)
str
>>> t = datetime.datetime.strptime(s,'%Y-%m-%d')
>>> t
datetime.datetime(2018, 3, 15, 0, 0)
时间转换为字符串
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2020, 2, 15, 18, 38, 38, 699776)
>>> txt = now.strftime('%Y/%m/%d')
>>> txt
'2020/02/15'
日期时间与字符串转换中常用的占位符
1、%Y:四位年份
2、%y:二位年份
3、%m:二位月份
4、%d:二位日期
5、%H:二位小时
6、%M:二位分钟
7、%S:二位秒数
8、%f:微秒
9、%w:星期数 0,1,···,6
······
时间差
两个时间点相减可得时间差
>>> d = datetime.datetime(2018,3,5,22,44)
>>> brithdate = datetime.datetime(2016,5,2,19,33,44)
>>> diff = d - brithdate
>>> diff
datetime.timedelta(days=672, seconds=11416) #672天零11416秒
>>> diff.days #天数
672
>>> diff.seconds #余下的秒数
11416
>>> diff.total_seconds() #总共包含的秒数
58072216.0
以某一时间点向后或向前推一段时间
>>> o = datetime.datetime(2008,8,8,20,8)
>>> result1 = o + datetime.timedelta(days = 100,seconds = 3000)
>>> result1
Out[99]: datetime.datetime(2008, 11, 16, 20, 58)
>>> result2 = o + datetime.timedelta(days = -100)
>>> result2
datetime.datetime(2008, 4, 30, 20, 8)
未完待续!