Python 解析式、生成器

一、标准库 datetime

1.1 datetime 模块
  • 对日期、时间、时间戳的处理
1.2 datetime
  • 类方法
    a. today() 返回本地时区当前时间的 datetime 对象
    b. now(tz=None) 返回当前时间的 datetime 对象,精确至微秒,若 tzNone,返回同 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)

  • yearmonthdayhourminutesecondmicrosecond,取 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))
示例.png
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)
示例.png
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]
示例.png
  • 思考
    1. 有这样的赋值语句 newlist = [print(i) for i in range(10)],请问打印出什么?newlist 打印出来是什么?

      示例.png

    2. 获取 20 以内的偶数,若同时 3 的倍数也打印 [i for i in range(20) if i % 2 == 0 elif i % 3 ==0] 行么?

      示例.png

四、列表解析进阶

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]
    
示例.png
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)]   # 字典与集合相同,不会去重
    
示例.png
示例.png
示例.png
示例.png
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]
示例.png

五、列表解析练习

5.1 练习(要求使用列表解析式完成)
  • 返回 1 - 10 平方的列表
[i ** 2 for i in range(11) if i > 0 ]
示例.png
  • 有一个列表 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)]
示例.png

六、生成器表达式 Generator expression

6.1 语法
  • (返回值 for 元素 in 可迭代对象 if 条件)
  • 列表解析式中的括号换成小括号即可
  • 返回一个生成器
示例.png
6.2 和列表解析式的区别
  • 生成器表达式是 按需计算(或称 惰性求值、延迟计算),需要的时候才计算值
  • 列表解析式是立即返回值
示例.png
6.3 生成器
  • 可迭代对象
  • 迭代器
示例.png
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 总结
  • 生成器

    1. 延迟计算
    2. 返回迭代器,可迭代
    3. 从前到后走完一遍,不能回头
  • 列表

    1. 立即计算
    2. 返回的不是迭代器,返回可迭代对象列表
    3. 从前导后走完一遍,可重新回头迭代
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()
示例.png
it = (x for x in range(10) if x % 2)
first = next(it)
second = next(it)
val = first + second
  • val 的值是什么?
val 的值为 4
示例.png
  • val = first + second 语句后能否再次 next(it)
因为此前计数器并未迭代完,所以可以继续 next() 调用
示例.png
6.7 和列表解析式的对比
  • 计算方式
    1. 生成器表达式延迟计算,列表解析式立即计算
  • 内存占用
    1. 单从返回值本身来说,生成器表达式
    2. 生成器没有数据,内存占用极少,它是使用时一个个返回数据,若将这些返回的数据合起来占用的内存和列表解析式差不多,但是,它不需要立即占用这么多内存
    3. 列表解析式构造新的列表需要立即占用内存,不管你是否立即使用这么多数据
  • 计算速度
    1. 但看计算时间,生成器表达式耗时非常短,列表解析式耗时长
    2. 但生成器本身并没有返回任何值,只返回了一个生成器对象
    3. 列表解析式构造并返回了一个新的列表,所以开起来耗时了

七、集合解析式

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 循环遍历

你可能感兴趣的:(Python 解析式、生成器)