一、标准库 datetime
1.1 datetime
模块
- 对日期、时间、时间戳的处理
1.2 datetime
类
- 类方法
a.today()
返回本地时区当前时间的datetime
对象
b.now(tz=None)
返回当前时间的datetime
对象,精确至微秒,若tz
为None
,返回同today()
c.utcnow()
没有时区的当前时间
d.fromtimestamp(timestamp, tz=None)
从一个时间戳返回一个datetime
对象
1.3 datetime
对象
timestamp()
返回一个到微秒的时间戳
a. 时间戳:格林威治时间 1970 年 1 月 1 日 0 点到现在的秒数构造方法
datetime.datetime(2020, 12, 6, 16, 29, 43, 79043)
year
、month
、day
、hour
、minute
、second
、microsecond
,取datetime
对象的年月日时分秒及微秒weekday()
返回周几,周一为0
,周日为6
isoweekday()
返回周几,周一为1
,周日为7
date()
返回日期date
对象time()
返回时间time
对象replace()
修改并返回新的时间isocalendar(0
返回一个三元组(年,周数,周几)
1.4 日期格式化
类方法
strptime(date_string, format)
,返回datetime
对象对象方法
strftime(format)
,返回字符串字符串
format
函数格式化
import datetime
dt = datetime.datetime.strptime("08/12/20 16:30", "%d/%m/%y %H:%M")
print(dt.strftime("%Y-%m-%d %H:%M:%S"))
print("{0:%Y}/{0:%m}/{0:%d} {0:%H}::{0:%H}::{0:%S}".format(dt))
print('{:%Y-%m-%d %H:%M:%S}'.format(dt))
1.5 timedelta
对象
datetime2 = datetime1 + timedelta
datetime2 = datetime1 - timedelta
timedelta = datetime1 - datetime2
- 构造方法
a.datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
b.year = datetime.timedelta(days=365)
-
total_seconds()
返回时间差的总秒数
二、标准库 time
2.1 time
-
time.sleep(secs)
将调用线程挂起指定的秒数
三、列表解析
3.1 举例
- 生成一个列表,元素 0 ~ 9,对每一个元素自增 1 后求平方返回新列表
lst = list(range(10))
newlst = list()
for i in lst:
newlst.append((i+1) ** 2)
print(newlst)
lst = list(range(10))
newlst = [ (i + 1) ** 2 for i in lst]
print(newlst)
3.2 语法
[ 返回值 for 元素 in 可迭代对象 if 条件]
- 使用中括号
[]
,内部是for
循环,if
条件语句可选 - 返回一个新列表
3.3 列表解析式是一种语法糖
- 编译器会优化,不会因为简写而影响效率,反而因优化提高了效率
- 减少程序员工作量,减少出错
- 简化了代码,但可读性增强
3.4 举例
- 获取 10 以内的偶数,比较执行效率
even = []
for i in range(10):
if i % 2 == 0:
even.append(i)
even = [ i for i in range(10) if i % 2 == 0]
- 思考
-
有这样的赋值语句
newlist = [print(i) for i in range(10)]
,请问打印出什么?newlist
打印出来是什么?
-
获取 20 以内的偶数,若同时 3 的倍数也打印
[i for i in range(20) if i % 2 == 0 elif i % 3 ==0]
行么?
-
四、列表解析进阶
4.1 [expr for item in iterable if cond1 if cond2]
- 等价于
ret = []
for item in iterable:
if cond1:
if cond2:
ret.appent(expr)
- 举例
- 20 以内,既能被 2 整除又能被 3 整除的数
[i for i in range(20) if i %2 == 0 and i % 3 == 0] [i for i in range(20) if i 5 2 == 0 if i % 3 == 0]
4.2 [expr for i in iteranle1 for j in iterable2]
- 等价于
ret = []
for i in iterable1:
for j in iterable2:
ret.append(expr)
- 举例
[(x, y) for x in 'abcde' for y in range(3)] [[x, y] for x in 'abcde' for y in range(3)] [{x, y} for x in 'abced' for y in range(3)] # 集合是整个生成列表中的元素,不会去重 [{x: y} for x in 'abced' for y in range(3)] # 字典与集合相同,不会去重
4.4 请问下面 3 中输出各是什么?为什么
[(i,j) for i in range(7) if i>4 for j in range(20,25) if j>23]
[(i,j) for i in range(7) for j in range(20,25) if i>4 if j>23]
[(i,j) for i in range(7) for j in range(20,25) if i>4 and j>23]
五、列表解析练习
5.1 练习(要求使用列表解析式完成)
- 返回 1 - 10 平方的列表
[i ** 2 for i in range(11) if i > 0 ]
- 有一个列表
lst = [1, 4, 9, 16, 2, 5, 10, 15]
,生成一个新列表,要求新列表元素是lst
相邻 2 项的和
lst = [1, 4, 9, 16, 2, 5, 10, 15]
[lst[i] + lst[i+1] for i in range(len(lst)) if i < (len(lst)-1)]
六、生成器表达式 Generator expression
6.1 语法
(返回值 for 元素 in 可迭代对象 if 条件)
- 列表解析式中的括号换成小括号即可
- 返回一个生成器
6.2 和列表解析式的区别
- 生成器表达式是 按需计算(或称 惰性求值、延迟计算),需要的时候才计算值
- 列表解析式是立即返回值
6.3 生成器
- 可迭代对象
- 迭代器
6.4 举例
g = ("{:04}".format(i) for i in range(1,11))
next(g)
for x in g:
print(x)
print('~~~~~~~~~~~~')
for x in g:
print(x)
- 列表对比
g = ["{:04}".format(i) for i in range(1,11)]
for x in g:
print(x)
print('~~~~~~~~~~~~')
for x in g:
print(x)
6.5 总结
-
生成器
- 延迟计算
- 返回迭代器,可迭代
- 从前到后走完一遍,不能回头
-
列表
- 立即计算
- 返回的不是迭代器,返回可迭代对象列表
- 从前导后走完一遍,可重新回头迭代
6.6 习题
it = (print("{}".format(i+1)) for i in range(2))
first = next(it)
second = next(it)
val = first + second
-
val
的值是什么
print() 函数是立即返回,所以不论是 first 还是 second 的值都是 None
所以 val 的运算结果会抛异常
-
val = first + second
语句之后能否再次next(it)
不可以 next() 了,因为此前的计数器是 range(2),程序已经迭代两次,所以不可再次 next()
it = (x for x in range(10) if x % 2)
first = next(it)
second = next(it)
val = first + second
-
val
的值是什么?
val 的值为 4
-
val = first + second
语句后能否再次next(it)
因为此前计数器并未迭代完,所以可以继续 next() 调用
6.7 和列表解析式的对比
- 计算方式
- 生成器表达式延迟计算,列表解析式立即计算
- 内存占用
- 单从返回值本身来说,生成器表达式
- 生成器没有数据,内存占用极少,它是使用时一个个返回数据,若将这些返回的数据合起来占用的内存和列表解析式差不多,但是,它不需要立即占用这么多内存
- 列表解析式构造新的列表需要立即占用内存,不管你是否立即使用这么多数据
- 计算速度
- 但看计算时间,生成器表达式耗时非常短,列表解析式耗时长
- 但生成器本身并没有返回任何值,只返回了一个生成器对象
- 列表解析式构造并返回了一个新的列表,所以开起来耗时了
七、集合解析式
7.1 语法
{ 返回值 for 元素 in 可迭代对象 if 条件 }
- 列表解析式的中括号换成大括号
{}
即可 - 立即返回一个集合
7.2 用法
{(x, x+1) for x in range(10)}
{[x] for x in range(10)}
八、字典解析式
8.1 语法
{ 返回值 for 元素 in 可迭代对象 if 条件 }
- 列表解析式中的括号换成大括号
{}
即可 - 使用
key:value
形式 - 立即返回一个字典
8.2 用法
{x:(x, x+1) for x in range(10)}
{x:[x, x+1] for x in range(10)}
{(x,):[x, x+1] for x in range(10)}
{[x]:[x, x+1] for x in range(10)}
{chr(0x41 +x):x**2 for x in range(10)}
{str(x):y for x in range(3) for y in range(4)}
- 等价于
ret = {}
for x in range(3):
for y in range(4):
ret[str(x)] = y
九、总结
- Python 2 引入列表解析式
- Python 2.4 引入生成器表达式
- Python 3 引入集合、字典解析式,并迁移至 Python 2.7
- 一般来说,应该多应用解析式,简短、高效
- 若一个解析式非常复杂,难以读懂,可考虑拆解成
for
循环 - 生成器和迭代器是不同的对象,但都是可迭代对象
- 可迭代对象范围更大,都可使用
for
循环遍历