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 循环遍历
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容