前言:
本文假定读者已经有了一定的Python 基础,看完过几本入门书籍。本文也不是那种快速参考手册 (可以很快的查询某个模块下的某个函数)。旨在聚焦几个最重要的主题,演示几种可能的高效解决方案,作为一个自己提升的记录。
本节主要介绍数字日期和时间、以及迭代的相关操作,上节讲的是字符串的操作
一、数字的操作
在开始本节内容之前,先看看舍入和格式化的区别。
x = 1.23456
format(x, '0.2f')
>>>'1.23'
round(x,2)
>>>1.23
"""
上面两个结果看上去一致,其实有本质区别,format结果是str,而round结果是float。
另外,需要注意的是round 函数返回离它最近的偶数。也就是说,对 1.5 或者 2.5 的舍入运算都会得到 2,
当你需求不是这样的时候考虑用其他方法,如math模块等。
"""
如果你的目的只是简单的输出一定宽度的数,你不需要使用 round() 函数。而仅仅只需要在格式化的时候指定精度即可。
另外需要知道的是,python中关于小数的精度的问题
a = 4.1
b = 4.3
c = a + b
print(a,b,c,sep="\t")
>>>4.1 4.3 8.399999999999999
以上情况,对于大多数使用到浮点的程序,没有必要使用round函数处理结果。尽管在计算的时候会有一点点小的误差,但是这些小的误差是能被理解与容忍的。如果不能允许这样的小误差 (比如涉及到金融领域),那么就得考虑使用 decimal 模块了
二、时间操作
1、字符串和日期的相互转换
字符串和时间的相互转换再实际的应用很多,所以必须写写,使用的模块时datetime模块。
时间转字符串
from datetime import datetime
datetime.strftime(datetime.now(),"%Y-%m-%d")
>>>'2021-08-26'
"""
第二个参数是时间格式参数
其中%Y 表示4位年份; %m代表两位月份;%d代表两位日期。
"""
字符串转时间
datetime.strptime('2021-08-26',"%Y-%m-%d")
>>>datetime.datetime(2021, 8, 26, 0, 0)
还有一点需要注意的是, strptime() 的性能要比你想象中的差很多,因为它是使用纯 Python 实现,并且必须处理所有的系统本地设置。如果你要在代码中需要解析大量的日期并且已经知了日期字符串的确切格式,可以自己实现一套解析方案来获取更好的性能。比如,如果你已经知道所以日期格式是 YYYY-MM-DD ,你可以像下面这样实现一个解析函数
def parse_ymd(s):
year_s, mon_s, day_s = s.split('-')
return datetime(int(year_s), int(mon_s), int(day_s))
上述方法在实际测试中,这个函数比 datetime.strptime() 快 7 倍多。如果你要处理大量的涉及到日期的数据的话,那么最好考虑下这个方案!
三、迭代操作
1、序列上索引值迭代
问题:你想在迭代一个序列的同时跟踪正在被处理的元素索引
内置的 enumerate() 函数可以很好的解决这个问题:
my_list = ['a', 'b', 'c']
for idx, val in enumerate(my_list):
print(idx, val, sep="\t\t")
>>> 0 a
1 b
2 c
# 为了按传统行号输出 (行号从 1 开始),你可以传递一个开始参数:
for idx, val in enumerate(my_list):
print(idx, val, sep="\t\t")
>>> 1 a
2 b
3 c
2、同时迭代多个序列
问题:你想同时迭代多个序列,每次分别从一个序列中取一个元素
为了同时迭代多个序列,使用 zip() 函数
xpts = [1, 5, 4, 2, 10, 7]
ypts = [101, 78, 37, 15, 62, 99, 89]
for x, y in zip(xpts,ypts):
print(x,y,sep="\t")
>>> 1 101
5 78
4 37
2 15
10 62
7 99
说明:zip(a, b) 会生成一个可返回元组 (x, y) 的迭代器,其中 x 来自 a,y 来自 b。一旦其中某个序列到底结尾,迭代宣告结束。因此迭代长度跟参数中最短序列长度一致
当然上述问题也可以解决,直接使用长的序列
from itertools import zip_longest
for i in zip_longest(xpts,ypts):
print(i)
>>> (1, 101)
(5, 78)
(4, 37)
(2, 15)
(10, 62)
(7, 99)
(None, 89)
# 你还可以通过参数,填充None值
for i in zip_longest(xpts,ypts,fillvalue=0):
print(i)
>>> (1, 101)
(5, 78)
(4, 37)
(2, 15)
(10, 62)
(7, 99)
(0, 89)
使用上述方法可以把两个可迭代列表快速生成字典
headers = ['name', 'shares', 'price']
values = ['ACME', 100, 490.1]
s = dict(zip(headers,values))
s
>>>{'name': 'ACME', 'shares': 100, 'price': 490.1}
3、不同集合上元素的迭代
from itertools import chain
a = [1, 2, 3, 4]
b = ['x', 'y', 'z']
for x in chain(a, b):
print(x)
>>>1
2
3
4
x
y
z
说明:itertools.chain() 接受一个或多个可迭代对象最为输入参数。然后创建一个迭代
器,依次连续的返回每个可迭代对象中的元素。这种方式要比先将序列合并再迭代要
高效的多。而且它不像a + b 操作会创建一个全新的序列并要求 a 和 b 的类型一致