> 文章列表 > 从零学习python - 11推导式 \\生成器与迭代器

从零学习python - 11推导式 \\生成器与迭代器

从零学习python - 11推导式 \生成器与迭代器

推导式 

# 列表推导式 [] 可以通过简单的语法

        对列表进行操作后返回符合条件的新列表 new_list = [x for x in list]

# 原列表
dict1 = {'name': 'aoa', 'age': 22, 'sex': 'boy'}
dict2 = {'name': 'bob', 'age': 23, 'sex': 'girl'}
dict3 = {'name': 'coc', 'age': 19, 'sex': 'girl'}
dict4 = {'name': 'dod', 'age': 18, 'sex': 'boy'}
list1 = [dict1, dict2, dict3, dict4]
# 返回list1中性别为boy的人
# 使用if结构跟着遍历后面
new_list = [user for user in list1 if user.get('sex') == 'boy']
print(new_list)  # [{'name': 'aoa', 'age': 22, 'sex': 'boy'}, {'name': 'dod', 'age': 18, 'sex': 'boy'}]
# 如果年纪低于20则加1岁 如果年纪大于20则加两岁
# 使用if... else ... 结构 是要放在for遍历前面 (有点类似于三目运算符)
new_list2 = [user['age'] + 1 if user.get('age') < 20 else user['age'] + 2 for user in list1]
print(new_list2) # [{'name': 'aoa', 'age': 22, 'sex': 'boy'}, {'name': 'dod', 'age': 18, 'sex': 'boy'}]
# 集合推导式 {} 格式用法相同 但集合会去除重复元素
list_num = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
set_num = {num+1 for num in list_num if num > 2}
print(set_num)      # {4, 5, 6}
# 字典推导式 将下面字典的key和value值互换位置
# 字典推导式 将下面字典的key和value值互换位置
dict_test = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'C'}
# dict.items()按元组返回字典内存放数据    常用遍历方法 for k,v in dict.items()
dict_fix = {value: key for key, value in dict_test.items()}
# 如果两个值相同,当k,v互换位置时只会保留最后一个元素的k,v
print(dict_fix)     # {'A': 'a', 'B': 'b', 'C': 'd'}

生成器

# 生成器: 使用列表推导式创建的新列表会受到内存的限制,列表容量有限.如果我们仅仅访问前面几个元素的话,还会浪费后面没有使用到的元素占用的空间.所以,如果列表元素可以按照某种算法推算出来,我们就可以一边循环一边推算出后续的元素来使用.
# 这种方法不用创建完整的list,节省空间.这种方法被成为生成器
# 得到生成器的方式:
# 1-通过列表推导式得到生成器:如果我们想用列表推导式来实现 只需要把[]换成()就可以
#    实现得到[0,3,6,9,...,27]
#    下面首先用列表推导式得到结果 这时这个list1会一直占用内存空间
list1 = [num*3 for num in range(10)]
print(list1)    # [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
#    如果我们想用列表推导式来实现 只需要把[]换成()就可以
g1 = (num*3 for num in range(10))
print(g1)    # <generator object_try <genexpr> at 0x00000237C61042E0> 这表示g1是一个生成器对象
print(g1.__next__())     # 0
print(g1.__next__())     # 3
print(g1.__next__())     # 6
print(next(g1))     # 9 有两种方法得到生成器中的元素 一个是g1.__next__() 还有系统自带函数 next(g1) 只有执行才会得到元素数值
# 我们可以使用循环来将g1生成器中的元素全部打印出来 如果前面有方法(__next__或者next(g1))拿走了其中的元素 那么我们后面的循环只会拿到剩余的元素
while True:try:print(next(g1))except:print('没有更多元素了!')break
# 得到生成器的方法:
# 2-借助函数完成  定义一个函数并使用yield关键字 调用函数并接收调用的结果 得到的结果就是生成器 yield关键字作用相当于 (return 并在这暂停)
#   只要函数中出现yield关键字,就说明这个函数不是函数了,已经变成生成器了   (yield n) 相当于 (return n + 暂停)操作
def get_num():n = 0while True:n += 1# print(n)#  (yield n) 相当于 (return n + 暂停)操作 当每调用一次next(g2)\\g2.__next__()时,就会跳转到这个关键字位置继续往下执行yield ng2 = get_num()  # g2是一个生成器对象
print(g2)   # <generator object_try get_num at 0x000001B84BBCDEE0>
print(next(g2))     # 1
# 练习 斐波那契数列
def fib(length):a, b = 0, 1n = 0while n < length:yield b     # 这里相当于return b后暂停住 等下个next(g3)调用时 接着往下执行a, b = b, a+bn += 1# 当生成器没有东西产生后 可以使用return返回一个语句以报错信息的形式提示return '没有更多元素了!'g3 = fib(8)
print(next(g3))     # 1
print(next(g3))     # 1
print(next(g3))     # 2
print(next(g3))     # 3
print(next(g3))     # 5
print(next(g3))     # 8
print(next(g3))     # 13
print(next(g3))     # 21
# print(next(g3))     # StopIteration: 没有更多元素了!
# 生成器方法: __next__(): 获取yield后的元素send(value):向每次生成器中传value 第一次调用要传入None 因为第一次会在yield暂停返回 所以不传None的话会报错当遇到yield关键字程序(return并暂停)后 send相当于程序在这个位置再次启动 并传进去一个值继续往下执行!就相当于 temp=message_test_01 我们send('参数')传过去的参数在yield关键字这个位置替换后重新启动!send()函数会将yield后的n返回 我们可以用参数接一下
def gen_test():n = 0while n < 5:temp = yield nprint(f'temp={temp}')n += 1return '没有更多元素了'g4 = gen_test()
n0 = g4.send(None)
print(f's0 = {n0}')     # n0 = 0n1 = g4.send('message_test_01')     # temp=message_test_01
print(f's1 = {n1}')     # n1 = 1n2 = g4.send('message_test_02')     # temp=message_test_02
print(f's2 = {n2}')     # n2 = 2print(g4.send('test3'))     # 3
# 生成器应用场景
# 进程 > 线程 > 协程 协程就是用生成器完成的
# 生成器的多应用
# 搬一块砖听一首歌曲,如果没有生成器的话程序执行顺序将会是先搬完砖再听歌,
# 如果使用生成器就可以控制程序运行.
# 生成器的多应用
def task1(n):for i in range(n):print(f'正在搬砖第{i + 1}块')yield# return '搬完了'def task2(n):for i in range(n):print(f'正在听歌第{i + 1}首')yield# return '听完了'g1 = task1(5)
g2 = task2(5)
while True:try:g1.__next__()g2.__next__()except:print('干完活儿了!')break

迭代

# 迭代:访问集合元素的一种方式,迭代器是一个可以记住遍历的位置的对象
#   迭代器对象只能从第一个元素开始访问,直到所有元素被访问完毕后结束
#   迭代器只能往前不能后退
#   可以被 next(对象) 函数调用并且不断返回下一个值的对象被称为迭代器:Iterator
# 可迭代的不一定就是迭代器 -> 生成器是可迭代的对象,是迭代器  字符串-列表-元组-集合-字典也是可迭代的,但不是迭代器
# 上述可迭代对象但不是迭代器的,可以使用方法 iter(字符串\\列表\\元组\\集合\\字典)来返回一个迭代器从而进行操作

 


print(isinstance('abcdefg', Iterable))  # True
list1 = [1, 2, 3, 4]
print(isinstance(list1, Iterable))  # True
tuple1 = (1, 2, 3, 4)
print(isinstance(tuple1, Iterable))  # True
set1 = {1, 2, 3, 4}
print(isinstance(set1, Iterable))  # True
dict1 = {'a': 'A', 'b': 'B'}
print(isinstance(dict1, Iterable))  # True
g1 = (x for x in range(5))
print(isinstance(g1, Iterable))  # True# print(next(list1))  # 'list' object is not an iterator
list_iter = iter(list1)
print(type(list_iter))  # <class 'list_iterator'> 通过iter()方法 将list变成了迭代器了
print(next(list_iter))  # 1# 其他\\列表\\元组\\集合\\字典同理 可以通过iter()方法变成迭代器使用

The End