Python知识点:推导式、生成器对象、打包与拆包

话说上周写了篇文章,留了个知识点,今天记录一下:

上周的文章:
Python用钉钉机器人发送消息并艾特多人
在这里插入图片描述

这里一共有三个知识点:

1、推导式

推导式这个东西,我是真的爱啊。语法简洁,含义清楚。
之前写过一篇文章:Python里的推导式。这里不再多说

j for j in user_id_list 
# 这句话就是推导式,推导式有4种:主要用途就是用极简代码循环推导出新的数据格式
# 列表(list)推导式
# 字典(dict)推导式
# 集合(set)推导式
# 元组(tuple)推导式(伪)

2、生成器对象(generator object)

什么是生成器对象?

生成器对象是一个可以生成数据的、可迭代的对象。
生成器对象在控制台输出结果为:<generator object num at 0x00000228BAB18AC0>

atUserIds = (j for j in user_id_list) 
# 可以叫他元组推导式(伪),但其实他是个生成器

先看个例子:下面这两段代码,区别只在于推导式的方式不同。一种是元组推导式(伪),一种是列表推导式。
元组推导式(伪)的结果是生成了一个生成器对象(generator object);
列表推导式的结果是生成了一个列表
在这里插入图片描述

那如何使用生成器对象(获取生成器里边的数据)?

方法1:用list列表

user_id_list = ['xiaoming','xiaohong','xiaohei','xiaolan','xiaolong']
atUserIds = (j for j in user_id_list)
list(atUserIds)
# ['xiaoming', 'xiaohong', 'xiaohei', 'xiaolan', 'xiaolong']

方法2:用for循环遍历

user_id_list = ['xiaoming','xiaohong','xiaohei','xiaolan','xiaolong']
atUserIds = (j for j in user_id_list)
for i in atUserIds:
    print(i)
# xiaoming
# xiaohong
# xiaohei
# xiaolan
# xiaolong

另一种生成一个生成器对象的方法:

刚才是用元组推导式(伪)来生成了一个生成器对象,那还有没有其他方式来生成生成器对象?
可以在函数中使用yield关键字,函数就变成了一个生成器。它是一种惰性计算。
如:

def num(start, stop, increment):
    while start < stop:
        yield start
        start += increment

a = num(1, 10, 1)
print('a:', a) # 此时执行的结果是:a: <generator object num at 0x00000228BAB18AC0>,生成了一个生成器对象
print('惰性计算第1次取值:', next(a))# 惰性计算,每次用next推动执行下一次
print('惰性计算第2次取值:', next(a))
print('惰性计算第3次取值:', next(a))
print('惰性计算第4次取值:', next(a))
print('惰性计算第5次取值:', next(a))
print('惰性计算第6次取值:', next(a))
print('惰性计算第7次取值:', next(a))
print('惰性计算第8次取值:', next(a))
print('惰性计算第9次取值:', next(a))# 一直到整个数据的最后一个数据,如果继续next,编译器会报错

# a: <generator object num at 0x00000228BAB18AC0>
# 惰性计算第1次取值: 1
# 惰性计算第2次取值: 2
# 惰性计算第3次取值: 3
# 惰性计算第4次取值: 4
# 惰性计算第5次取值: 5
# 惰性计算第6次取值: 6
# 惰性计算第7次取值: 7
# 惰性计算第8次取值: 8
# 惰性计算第9次取值: 9

函数里有了yield后,执行到yield就会停住,需要用next才会推动走下一步。所以生成器函数即使是有无限循环也没关系。
这样有个好处:节省内存空间和算力、有效规避了死循环带来的资源消耗。

3、打包和拆包

*atUserIds 
# 拆包

在java里,交换两个变量的值,需要用到第三个变量,但是在Python中可以省去这个步骤。直接用下面的代码即可实现变量的交换:

a = 1
b = 2
a,b = b,a

这其实就是个打包和拆包的过程。

最简单的拆包操作:

tuple1 = (1, 2, 3) # 先定义一个元组
a,b,c = tuple1 # 把元组的数值拆到变量里。元组的值的个数和变量个数一致(也可以不一致,不一致的时候就需要用到*进行打包操作)。这就是拆包
print(a,b,c)
# 1 2 3
print(*tuple1) # 也可以直接用*拆出来打印
# 1 2 3

最简单的打包操作:

tuple2 = (4, 5, 6, 7, 8, 9)# 先定义一个元组
a,*b,c = tuple2 # a和c代表头和尾,中间的打包的变量b中。中间所有的值都赋值给b的操作,就是打包
print(a,b,c)
# 4 [5, 6, 7, 8] 9
# 可以看出,b的数据类型是list列表。

print(*tuple2)# 也可以直接用*拆出来打印
# 4 5 6 7 8 9

回归原题:
在这里插入图片描述

源代码里的[*atUserIds]这句话,可以拆成两步来看:
1、*atUserIds:把传入的生成器对象,拆包
2、[]:将拆包的结果放到了列表里
这句话相当于是:list(atUserIds)

最后

关于[*atUserIds]和list(atUserIds)的对比,再用一个直观的例子说一下。如下:

# 将生成器对象处理成列表:方法1
user_id_list = ['xiaoming','xiaohong','xiaohei','xiaolan','xiaolong']
atUserIds = (j for j in user_id_list)

list_a = list(atUserIds)
print("list_a:",list_a)
# list_a: ['xiaoming', 'xiaohong', 'xiaohei', 'xiaolan', 'xiaolong']
# 将生成器对象处理成列表:方法2
user_id_list = ['xiaoming','xiaohong','xiaohei','xiaolan','xiaolong']
atUserIds = (j for j in user_id_list)

gen_a =[*atUserIds]
print("gen_a:",gen_a)
# gen_a: ['xiaoming', 'xiaohong', 'xiaohei', 'xiaolan', 'xiaolong']

以上内容是查阅资料之后,亲自用Python3.9版本试验之后的结果。如有理解或者表述不到位的,还请指出。

猜你喜欢

转载自blog.csdn.net/xkukeer/article/details/125761126
今日推荐