003---生成器 & 迭代器

生成器 & 迭代器

列表生成式

现在有个需求,列表[1, 2, 3, 4, 5, 6, 7, 8, 9],将列表里的每个值加1。

  • 二逼青年版

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

b = []
for item in a:
    b.append(item + 1)
a = b
print(a)
  • 普通青年版
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

for index, ele in enumerate(a, 0):
    a[index] += 1

print(a)
  • 文艺版(lambda + map 搭配使用)
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

a = list(map(lambda x:x+1,a))
print(a)

  • 装逼青年版
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

print([i + 1 for i in a])
  • 这种写法就是列表生成式
  • 习题:利用列表生成式一行代码实现9 * 9乘法表
print('\n'.join([''.join(['%d * %d = %-3d' % (i, j, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))

生成器

  • 通过列表生成式,可以直接创建一个列表,但是毕竟内存有限,列表的容量也是有限的。创建一个包含100万个元素的列表,但是我们仅仅需要访问前面几个元素,这就造成了内存大量白白浪费。
  • 在python中有一种更好的解决方式,边循环边计算的机制。称为(generator)
  • 简单创建生成器(只需要把列表生成器的方括号改成括号)
g = (i for i in range(5))

print(type(g),g.next())
  • next()取值和for循环取值
# 使用next()取值
g = (i for i in range(5))
print(type(g))
print('开始取值')
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# print(next(g)) # 报错:StopIteration,因为取不到值了

# 基本上不会使用next(),正确应该使用for循环。而且还不需要担心会报错。拿不到函数return返回值
g = (i for i in range(10))
for i in g:
    print(i)
  • 斐波拉契
# 斐波拉契:1 1 2 3 5 8 13 21
def fbi(num):
    n, a, b = 0, 0, 1
    while n < num:
        yield b  # # 到这停止,可以理解为冻结当前代码。并且,把值返回给外面的next()
        print(a, b)
        a, b = b, a + b
        n += 1


for i in fbi(2):
    print(i)
  • 代码解析:

    • return 和 yield 的区别
      • 返回并终止函数
      • 返回数据,并冻结当前的执行过程。
      • next()唤醒冻结函数的执行过程,继续执行,直到遇到下一个yield
    • 函数加了yield之后
      • 函数()就得到了生成器,不next()不开始执行。
      • return 在生成器里,代表生成器的终止,直接报错
  • 深入

# 生成器send,相当于唤醒。
def work(n):
    count = 0
    while count < n:
        count += 1
        sign = yield count
        print('sign的值:',sign)
        if not sign:
            yield count + 2


new_range = work(4)
# res = next(new_range)           # 开始第一次取值 拿到一个1
# print(res)                      # 1
# res1 = new_range.send(True)     # 第二次取值 发送一个true  函数遇到true 循环
# print(res1)                     # 2
# res2 = new_range.send(False)    # 第三次取值 n=3
# print(res2)

迭代器

  • 可以作用for循环的类型:

    • 集合类型:str、list、tuple、dict、set
    • generator:生成器和带yield的函数

    这些类型称为可迭代对象:iterable

    from collections import Iterable
    
    print(isinstance([],Iterable))
    print(isinstance('',Iterable))
    print(isinstance({},Iterable))
    print(isinstance(set(),Iterable))
    print(isinstance((i for i in range(2)),Iterable))
    
    
  • 生成器不仅可以作用域for还可以被next()不断取值,直到没有数据可取

from collections import Iterator
print(isinstance((i for i in range(2)),Iterator))

总结

  • 凡是可以作用于for循环的对象都是可迭代对象,Iterable
  • 凡是可以作用于next()的对象都是迭代器,Iterator
  • 集合数据类型虽然不是迭代器,但是可以通过iter()函数变成Iterator。
posted @ 2019-01-30 12:41  爬呀爬Xjm  阅读(115)  评论(0编辑  收藏  举报