PS:原先是想直接进入功能开发,要用到什么函数时再建立,这样也容易熟悉每一个函数的由来和使用方法,但考虑到这样操做,到时会常常在不一样文件间切换,很差描述,容易形成混乱,因此仍是使用函数库这种方式来讲明。python
下面来讲说工具函数包,若是想要快速学会一个新的框架,首先要作的事情就是熟悉工具函数包,一方面,能快速知道有哪些基本功能能够直接调用,不用重复造轮子;另外一方面,查看项目代码时,会比较快的进入角色,能看明白不少代码是作什么用的,由于工具函数包被调用的机率是最大的。web
那么怎么学习呢?固然是有节奏有计划的一步步深刻了,咱们能够从上到下逐个查看研究,经过查看代码,咱们能够基本了解这个包有什么功能,但也仅仅是了解而已,想要真正掌握,必需要去使用它们,最直接的方法就是编写测试用例进行测试,这样就能够很快熟悉并掌握这些函数具体有什么功能与限制。安全
PS:你们在学习工具函数,或其余封装好的类或函数时,在开始时不须要去知道它里面每一行代码是作什么用的,为何要那么写,只须要知道输入什么参数会得出什么值就能够了,这就是你们所说的封装。咱们要开汽车,不须要知道它是怎么造出来的,发动机是怎么运行的,只须要知道怎么操做(接口)就能够了。框架
我之前遇到过几位爱钻牛角尖的开发者,想弄明白每一行代码为何要那样写,当那一行所调用的函数看不懂时,就会再深刻一层,看看它更底层是什么原理......就这样,通常人用几分钟就能够知道怎么用的,他花几天也弄不明白,花了好长时间也无法写代码。对于初学者来讲,学习一个函数怎么使用,不要钻牛角尖,去研究它的内部是怎么运行的,要研究也要等到你之后精通了再说,否则你看到一个函数就去看它的源码,而后源码中又会调用其余库的源码,其余库的源码又会调用python的内核代码,难道你要搞定python的内核代码后才能够开始开发吗?你能搞的定python内核你就是超级大牛了,能够本身开发一种新语言出来了。ide
因此说想要快速学习,最好的办法就是知道这个封装好的函数是干吗的,它须要输入什么参数,会返回什么内容就已经够了。而最快的熟悉方法就是写单元测试,用你能想到的办法去测试,这样就知道何时出错,何时正常。函数
熟悉相关工具函数:工具
convert_helper.py是类型转换包,全部字符串转数值、字符串转日期、字符串日期转时间戳等各类类型转换函数,均可以放到这里来。单元测试
1 #!/usr/bin/evn python 2 # coding=utf-8 3 4 import decimal 5 import datetime 6 7 8 ############################################# 9 # 数值型转换函数 10 ############################################# 11 def to_int(text): 12 """将字符串安全转换为int类型,转换失败时默认值为0""" 13 try: 14 return int(text) 15 except: 16 return 0 17 18 19 def to_int0(text): 20 """将字符串安全转换为int类型,当int值小于0时,返回0""" 21 result = to_int(text) 22 23 # 判断转换后的结果值是否小于0,是的话返回0 24 if not result or result < 0: 25 return 0 26 else: 27 return result 28 29 30 def to_int1(text): 31 """将字符串安全转换为int类型,当int值小于1时,返回1""" 32 result = to_int(text) 33 34 # 判断转换后的结果值是否小于1,是的话返回1 35 if not result or result < 1: 36 return 1 37 else: 38 return result 39 40 41 def to_float(text): 42 """将字符串安全转换为float类型""" 43 try: 44 return float(text) 45 except: 46 return 0.0 47 48 49 def to_decimal(text): 50 """将字符串安全转换为int类型""" 51 try: 52 return decimal.Decimal(text) 53 except: 54 return 0 55 56 57 ############################################# 58 # 日期型转换函数 59 ############################################# 60 def to_datetime(text): 61 """字符串转时间""" 62 if not text: 63 return None 64 65 # 定义字典根据时间字符串匹配不一样的格式 66 time_dict = { 67 1: "%Y-%m-%d %H:%M:%S.%f", 68 2: "%Y-%m-%d %H:%M", 69 3: "%Y-%m-%d %H:%M:%S", 70 } 71 # 若是中间含有时间部分就用:判断 72 try: 73 if str(text).find('.') > -1: 74 return datetime.datetime.strptime(text, time_dict[1]) 75 elif ':' in text: 76 time_list = text.split(':') 77 return datetime.datetime.strptime(text, time_dict[len(time_list)]) 78 else: 79 return datetime.datetime.strptime(text, "%Y-%m-%d") 80 except: 81 return None 82 83 84 def to_date(text): 85 """字符串转日期""" 86 d = to_datetime(text) 87 if d: 88 return d.date() 89 90 91 def to_timestamp10(text): 92 """将时间格式的字符串转化为长度为10位长度的时间戳""" 93 d = to_datetime(text) 94 if d: 95 return int(d.timestamp()) 96 else: 97 return 0 98 99 100 def to_timestamp13(text): 101 """将时间格式的字符串转化为长度为13位长度的时间戳""" 102 d = to_datetime(text) 103 if d: 104 return int(d.timestamp() * 1000) 105 else: 106 return 0
好比说字符转int函数学习
def to_int(text): """将字符串安全转换为int类型,转换失败时默认值为0""" try: return int(text) except: return 0
这里咱们用try...except...来捕捉转换函数出现的异常,当出现异常时咱们设置它的默认值为0,让咱们的系统变的更加健壮,不会由于转换失败而崩溃。测试
使用这个函数转换出现异常时,咱们只是直接将它转换为0,不作记录,由于数值转换时直接抛出异常会让用户体验更差劲,另外对于数值类型来讲,若是得出的结果都是0而不是指望值,这也很容易排查出来,在后面章节会讲到web端接收到的请求值都会记录下来,方便咱们排错。
def to_int0(text): """将字符串安全转换为int类型,当int值小于0时,返回0""" result = to_int(text) # 判断转换后的结果值是否小于0,是的话返回0 if not result or result < 0: return 0 else: return result def to_int1(text): """将字符串安全转换为int类型,当int值小于1时,返回1""" result = to_int(text) # 判断转换后的结果值是否小于1,是的话返回1 if not result or result < 1: return 1 else: return result
你们可能会奇怪,为何要增长这两个多余的函数?事实上,这两个函数使用频率比前面那个会更高,由于咱们在平常使用当中,常常会要求数值不能小于0或小于1,而to_int()函数转换时,用户若是输入了负数,虽然转换成功了,但这个值却不是咱们想要的结果,若是每次都要加上一段代码对值进行判断,那会更加麻烦,因此进行了再次封装,多出来to_int0()和to_int()1两个函数。
对这几个函数咱们用unittest测试一下,看看结果。
咱们在test文件夹建立一个convert_helper_test.py文件,并编写测试代码,用来测试输入各类值,看看是否获得咱们指望的值。(PS:使用debug运行时,光标在那个函数中,unittest就会运行那个测试函数,因此若是有多个测试函数要运行时,最好用鼠标点击一下main函数,即入口函数,再运行debug,这样所有测试函数都会运行到)
#!/usr/bin/evn python # coding=utf-8 import datetime import unittest from common import convert_helper class ConvertHelperTest(unittest.TestCase): """转换操做包测试类""" def setUp(self): """初始化测试环境""" print('------ini------') def tearDown(self): """清理测试环境""" print('------clear------') def test_to_int(self): self.assertEqual(convert_helper.to_int('1'), 1) self.assertEqual(convert_helper.to_int('1.0'), 0) self.assertEqual(convert_helper.to_int('1a'), 0) self.assertEqual(convert_helper.to_int('aaa'), 0) self.assertEqual(convert_helper.to_int(''), 0) self.assertEqual(convert_helper.to_int(None), 0) self.assertEqual(convert_helper.to_int('-1'), -1) self.assertEqual(convert_helper.to_int(10), 10) self.assertEqual(convert_helper.to_int(-10), -10) self.assertEqual(convert_helper.to_int0('1'), 1) self.assertEqual(convert_helper.to_int0('1.0'), 0) self.assertEqual(convert_helper.to_int0('1a'), 0) self.assertEqual(convert_helper.to_int0('aaa'), 0) self.assertEqual(convert_helper.to_int0(''), 0) self.assertEqual(convert_helper.to_int0(None), 0) self.assertEqual(convert_helper.to_int0('-1'), 0) self.assertEqual(convert_helper.to_int0(10), 10) self.assertEqual(convert_helper.to_int0(-10), 0) self.assertEqual(convert_helper.to_int1('1'), 1) self.assertEqual(convert_helper.to_int1('1.0'), 1) self.assertEqual(convert_helper.to_int1('1a'), 1) self.assertEqual(convert_helper.to_int1('aaa'), 1) self.assertEqual(convert_helper.to_int1(''), 1) self.assertEqual(convert_helper.to_int1(None), 1) self.assertEqual(convert_helper.to_int1('-1'), 1) self.assertEqual(convert_helper.to_int1(10), 10) self.assertEqual(convert_helper.to_int1(-10), 1) if __name__ == '__main__': unittest.main()
在这个单元测试中,咱们使用的是python自带的unittest这个模块。
这里咱们调用了unittest的断言函数assertEqual(等于)来判断convert_helper包的to_int()、to_int0()、to_int1()函数的执行结果是否和咱们设定的值一致
经过测试能够看到,to_int系列函数的值是不同的:
输入值 | 调用函数 to_int() |
调用函数 to_int0() |
调用函数 to_int1() |
非数值型字符串 | 0 | 0 | 1 |
-1 | -1 | 0 | 1 |
10 | 10 | 10 | 10 |
unittest还有不少其余断言函数提供给咱们使用,好比assertNotEqual(不等于)、assertGreaterEqual(大于等于)、assertGreater(大于)、assertAlmostEqual(约等于)、assertIsNotNone(不等于None)、assertIn(in)、assertNotIn(not in)、assertIs(is)、assertDictEqual(字典比较)、assertListEqual(列表比较)......还有好多其余类型的判断处理。
使用单元测试除了上面所说的好处外,它还能够帮助咱们实现自动化测试。好比说项目开发的过程当中,有人修改了底层的这些工具函数,增长了新的判断处理,这可能只是一个小小的修改,你们都以为不会有什么问题,但有可能这点小改动会形成灾难性的故障(我本人就试过,有些很小很小的改动,对多个合做客户调用的接口测试过也没有问题,可没想到遗漏了另一个客户的测试,而后形成那个合做客户的用户访问都出现异常,没法从个人系统中读取到数据)。而有了这些已经实现了的自动化测试用例在,修改过或上线前,只须要简单的点一下运行,就能够帮咱们对全部函数都进行全面的测试,帮咱们及时找到可能出现的Bug。
对于float类型数值和decimal类型数值,若是有须要,你们也能够本身去添加0或1最小值的判断。
to_datetime()函数,会根据输入的日期字符串格式,转换成对应的日期(如:2017-09-01)、日期时间(2017-09-01 11:11)、日期时分秒(2017-09-01 11:11:11)、日期时分秒毫秒类型(2017-09-01 11:11:11.111),获得的值是datetime类型
固然也能够直接使用打印输出结果的方式来进行测试,不过结果没法自动进行判断是不是咱们指望的值
def test_to_datetime(self): print('---test_to_datetime---') print(convert_helper.to_datetime(None)) print(convert_helper.to_datetime('')) print(convert_helper.to_datetime('xxx')) print(convert_helper.to_datetime('2017-09-01')) print(convert_helper.to_datetime('2017-09-01 11:11')) print(convert_helper.to_datetime('2017-09-0111:11')) print(convert_helper.to_datetime('2017-09-01 11:11:11')) print(convert_helper.to_datetime('2017-09-01 11:11:11.111'))
获得的结果是:
---test_to_datetime--- None None None 2017-09-01 00:00:00 2017-09-01 11:11:00 None 2017-09-01 11:11:11 2017-09-01 11:11:11.111000
对于日期类的测试若是使用断言,咱们一般要建立生成一个日期变量,而后在进行判断
self.assertEqual(convert_helper.to_datetime(None), None) self.assertEqual(convert_helper.to_datetime(''), None) self.assertEqual(convert_helper.to_datetime('xxx'), None) result = datetime.datetime(2017, 9, 1) self.assertEqual(convert_helper.to_datetime('2017-09-01'), result) result = datetime.datetime(2017, 9, 1, 11, 11) self.assertEqual(convert_helper.to_datetime('2017-09-01 11:11'), result) self.assertEqual(convert_helper.to_datetime('2017-09-0111:11'), None) result = datetime.datetime(2017, 9, 1, 11, 11, 11) self.assertEqual(convert_helper.to_datetime('2017-09-01 11:11:11'), result) result = datetime.datetime(2017, 9, 1, 11, 11, 11, 111000) self.assertEqual(convert_helper.to_datetime('2017-09-01 11:11:11.111'), result)
to_date()函数是用来将各类格式的日期字符串,转换为只含年月日(2017-09-01)的日期格式,具体你们使用代码测试一下就知道了
to_timestamp10()函数是用来将各类格式的日期字符串,转换为长度为10位长度的时间戳
to_timestamp13()函数是用来将各类格式的日期字符串,转换为长度为13位长度的时间戳
具体这些测试例子,可下载文章后面的源码包查看了解
下面咱们来熟悉一下datetime_helper.py这个日期函数操做包,这个包里的函数类型主要有两大类,一种是日期类型转换,将日期类型格式化为字符串类型或转换为数值类型;另外一种是对日期类型的比较或运算。
先上代码:
1 #!/usr/bin/evn python 2 # coding=utf-8 3 4 import time 5 import datetime 6 7 8 def to_date(dt): 9 """将时间格式化为日期字符串""" 10 if isinstance(dt, datetime.datetime): 11 return dt.strftime('%Y-%m-%d') 12 elif isinstance(dt, datetime.date): 13 return dt.strftime('%Y-%m-%d') 14 else: 15 raise Exception("日期类型错误") 16 17 18 def to_datetime(dt): 19 """将时间格式化为日期时间字符串""" 20 if isinstance(dt, datetime.datetime): 21 return dt.strftime('%Y-%m-%d %H:%M:%S') 22 elif isinstance(dt, datetime.date): 23 return dt.strftime('%Y-%m-%d') 24 else: 25 raise Exception("日期类型错误") 26 27 28 def to_number(): 29 """当前时间转换为年月日时分秒毫秒共10位数的字符串""" 30 return datetime.datetime.now().strftime('%Y%m%d%H%M%S') 31 32 33 def to_timestamp10(): 34 """获取当前时间长度为10位长度的时间戳""" 35 return int(time.time()) 36 37 38 def to_timestamp13(): 39 """获取当前时间长度为13位长度的时间戳""" 40 return int(time.time() * 1000) 41 42 43 def timedelta(sign, dt, value): 44 """ 45 对指定时间进行加减运算,几秒、几分、几小时、几日、几周、几月、几年 46 sign: y = 年, m = 月, w = 周, d = 日, h = 时, n = 分钟, s = 秒 47 dt: 日期,只能是datetime或datetime.date类型 48 value: 加减的数值 49 return: 返回运算后的datetime类型值 50 """ 51 if not isinstance(dt, datetime.datetime) and not isinstance(dt, datetime.date): 52 raise Exception("日期类型错误") 53 54 if sign == 'y': 55 year = dt.year + value 56 if isinstance(dt, datetime.date): 57 return datetime.datetime(year, dt.month, dt.day) 58 elif isinstance(dt, datetime.datetime): 59 return datetime.datetime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) 60 else: 61 return None 62 elif sign == 'm': 63 year = dt.year 64 month = dt.month + value 65 ### 若是月份加减后超出范围,则须要计算一下,对年份进行处理 ### 66 # 若是月份加减后等于0时,须要特殊处理一下 67 if month == 0: 68 year = year - 1 69 month = 12 70 else: 71 # 对年月进行处理 72 year = year + month // 12 73 month = month % 12 74 if isinstance(dt, datetime.date): 75 return datetime.datetime(year, month, dt.day) 76 elif isinstance(dt, datetime.datetime): 77 return datetime.datetime(year, month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) 78 else: 79 return None 80 elif sign == 'w': 81 delta = datetime.timedelta(weeks=value) 82 elif sign == 'd': 83 delta = datetime.timedelta(days=value) 84 elif sign == 'h': 85 delta = datetime.timedelta(hours=value) 86 elif sign == 'n': 87 delta = datetime.timedelta(minutes=value) 88 elif sign == 's': 89 delta = datetime.timedelta(seconds=value) 90 else: 91 return None 92 93 return dt + delta
to开头的函数都是时间类型转换函数(PS:convert_helper.py包里是对日期格式字符串转为时间类型,而datetime_helper.py里全部操做,都是对时间类型进行处理的,将它们转为其余格式)
好比to_date()和to_datetime(),这两个函数分别是将时间类型格式化为年月日(2017-09-01)、年月日时分秒(2017-09-01 11:11:11)或数值字符串(20170901111111)
def to_date(dt): """将时间格式化为日期字符串""" if isinstance(dt, datetime.datetime): return dt.strftime('%Y-%m-%d') elif isinstance(dt, datetime.date): return dt.strftime('%Y-%m-%d') else: raise Exception("日期格式错误") def to_datetime(dt): """将时间格式化为日期时间字符串""" if isinstance(dt, datetime.datetime): return dt.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(dt, datetime.date): return dt.strftime('%Y-%m-%d') else: raise Exception("日期格式错误") def to_number(): """将当前时间转换为年月日时分秒毫秒共14位数的字符串""" return datetime.datetime.now().strftime('%Y%m%d%H%M%S')
而to_timestamp10()和to_timestamp13()是获取当前时间的时间戳
def to_timestamp10(): """获取当前时间长度为10位长度的时间戳""" return int(time.time()) def to_timestamp13(): """获取当前时间长度为13位长度的时间戳""" return int(time.time() * 1000)
对这种输出类型的函数测试,咱们测试时直接打印到控制台就能够了
在test文件夹中建立datetime_helper_test.py文件,而后经过打印来查看各函数会输出什么值
#!/usr/bin/evn python # coding=utf-8 import datetime import unittest from common import datetime_helper class DatetimeHelperTest(unittest.TestCase): """日期函数操做包测试类""" def setUp(self): """初始化测试环境""" print('------ini------') def tearDown(self): """清理测试环境""" print('------clear------') def test(self): dt = datetime.datetime.now() print(datetime_helper.to_datetime(dt)) print(datetime_helper.to_date(dt)) print(datetime_helper.to_number()) print(datetime_helper.to_timestamp10()) print(datetime_helper.to_timestamp13()) if __name__ == '__main__': unittest.main()
运行后打印到控制台上的值:
------ini------ 2017-09-01 18:45:39 2017-09-01 20170901184539 1504262739 1504262739217 ------clear------
1 def timedelta(sign, dt, value): 2 """ 3 对指定时间进行加减运算,几秒、几分、几小时、几日、几周、几月、几年 4 sign: y = 年, m = 月, w = 周, d = 日, h = 时, n = 分钟, s = 秒 5 dt: 日期,只能是datetime或datetime.date类型 6 value: 加减的数值 7 return: 返回运算后的datetime类型值 8 """ 9 if not isinstance(dt, datetime.datetime) and not isinstance(dt, datetime.date): 10 raise Exception("日期类型错误") 11 12 if sign == 'y': 13 year = dt.year + value 14 if isinstance(dt, datetime.date): 15 return datetime.datetime(year, dt.month, dt.day) 16 elif isinstance(dt, datetime.datetime): 17 return datetime.datetime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) 18 else: 19 return None 20 elif sign == 'm': 21 year = dt.year 22 month = dt.month + value 23 ### 若是月份加减后超出范围,则须要计算一下,对年份进行处理 ### 24 # 若是月份加减后等于0时,须要特殊处理一下 25 if month == 0: 26 year = year - 1 27 month = 12 28 else: 29 # 对年月进行处理 30 year = year + month // 12 31 month = month % 12 32 if isinstance(dt, datetime.date): 33 return datetime.datetime(year, month, dt.day) 34 elif isinstance(dt, datetime.datetime): 35 return datetime.datetime(year, month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) 36 else: 37 return None 38 elif sign == 'w': 39 delta = datetime.timedelta(weeks=value) 40 elif sign == 'd': 41 delta = datetime.timedelta(days=value) 42 elif sign == 'h': 43 delta = datetime.timedelta(hours=value) 44 elif sign == 'n': 45 delta = datetime.timedelta(minutes=value) 46 elif sign == 's': 47 delta = datetime.timedelta(seconds=value) 48 else: 49 return None 50 51 return dt + delta
timedelta()函数,它主要用于时间的加减运算,能够得出加减几秒、几分、几小时、几日、几周、几月、几年后的时间值是什么,这个函数在实际开发中使用频率还算是挺高的。
PS:原datetime.timedelta函数没有对年和月的加减运算,对这个我进行了扩展,增长了年和月的加减计算
def test_timedelta(self): print('---test_timedelta---') result = datetime.datetime(2018, 9, 1) print(result) self.assertEqual(datetime_helper.timedelta('y', datetime.datetime(2017, 9, 1), 1), result) result = datetime.datetime(2016, 9, 1) print(result) self.assertEqual(datetime_helper.timedelta('y', datetime.datetime(2017, 9, 1), -1), result) result = datetime.datetime(2018, 3, 1) print(result) self.assertEqual(datetime_helper.timedelta('m', datetime.datetime(2017, 9, 1), 6), result) result = datetime.datetime(2017, 3, 1) print(result) self.assertEqual(datetime_helper.timedelta('m', datetime.datetime(2017, 9, 1), -6), result) result = datetime.datetime(2017, 3, 1) print(result) self.assertEqual(datetime_helper.timedelta('m', datetime.datetime(2017, 9, 1), -6), result) result = datetime.datetime(2017, 9, 8) print(result) self.assertEqual(datetime_helper.timedelta('w', datetime.datetime(2017, 9, 1), 1), result) result = datetime.datetime(2017, 8, 25) print(result) self.assertEqual(datetime_helper.timedelta('w', datetime.datetime(2017, 9, 1), -1), result) result = datetime.datetime(2017, 9, 2) print(result) self.assertEqual(datetime_helper.timedelta('d', datetime.datetime(2017, 9, 1), 1), result) result = datetime.datetime(2017, 8, 31) print(result) self.assertEqual(datetime_helper.timedelta('d', datetime.datetime(2017, 9, 1), -1), result) result = datetime.datetime(2017, 9, 1, 1) print(result) self.assertEqual(datetime_helper.timedelta('h', datetime.datetime(2017, 9, 1), 1), result) result = datetime.datetime(2017, 8, 31, 23) print(result) self.assertEqual(datetime_helper.timedelta('h', datetime.datetime(2017, 9, 1), -1), result) result = datetime.datetime(2017, 9, 1, 0, 1) print(result) self.assertEqual(datetime_helper.timedelta('n', datetime.datetime(2017, 9, 1), 1), result) result = datetime.datetime(2017, 8, 31, 23, 59) print(result) self.assertEqual(datetime_helper.timedelta('n', datetime.datetime(2017, 9, 1), -1), result) result = datetime.datetime(2017, 9, 1, 0, 0, 1) print(result) self.assertEqual(datetime_helper.timedelta('s', datetime.datetime(2017, 9, 1), 1), result) result = datetime.datetime(2017, 8, 31, 23, 59, 59) print(result) self.assertEqual(datetime_helper.timedelta('s', datetime.datetime(2017, 9, 1), -1), result)
运行后打印到控制台上的值:
------ini------ ---test_timedelta--- 2018-09-01 00:00:00 2016-09-01 00:00:00 2018-03-01 00:00:00 2017-03-01 00:00:00 2017-03-01 00:00:00 2017-09-08 00:00:00 2017-08-25 00:00:00 2017-09-02 00:00:00 2017-08-31 00:00:00 2017-09-01 01:00:00 2017-08-31 23:00:00 2017-09-01 00:01:00 2017-08-31 23:59:00 2017-09-01 00:00:01 2017-08-31 23:59:59 ------clear------
版权声明:本文原创发表于 博客园,做者为 AllEmpty 本文欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然视为侵权。
python开发QQ群:669058475(本群已满)、733466321(能够加2群) 做者博客:http://www.cnblogs.com/EmptyFS/