【python基础】可迭代对象和迭代器和生成器

参考自:https://www.cnblogs.com/wj-1314/p/8490822.html

参考自:https://blog.csdn.net/qq_39521554/article/details/79864889

可迭代对象(iterable)

可迭代对象(iterable):可直接作用于for循环的对象的统称,如list、tuple、dict、set、str、生成器等。

可以用isinstance()判断一个对象是否为iterable:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

迭代器(iterator)

迭代器(iterator):可以作用于next()函数的对象的统称。

python中iterator对象表示一个数据流,不能提前知道数据流的长度,只能通过next()调用。所以说iterator的计算是惰性的,只有在需要返回的时候才会返回下一个数据。

可以用isinstance()判断一个对象是否为iterator:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

用iter()函数可以把listdictstrIterable变成Iterator:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

用next()函数,使iterator返回下一个值:

>>> a = iter([1,2,3])
>>> print a.next()
1
>>> print a.next()
2
>>> print a.next()
3
>>> print a.next()
Traceback (most recent call last):
  File "G:/study/python/code/book_test/test.py", line 18, in <module>
    print a.next()
StopIteration

生成器(generator)

生成器(generator):使用了yield的函数叫做generator

它是特殊的iterator

每次遇到 yield 时,函数会暂停并保存当前所有的运行信息(挂起),返回 yield 的值(类似return), 并在下一次执行 next() 方法时从yield下一行继续运行(重新拾起)。

实现一个生成器方法1,用生成器函数:

# 用生成器实现斐波那契数列
def fib(max):
    n,a,b =0,0,1
    while n < max:
        yield b
        a,b =b,a+b
        n = n+1

for i in fib(6):
    print(i)
     
结果:
1
1
2
3
5
8

实现一个生成器方法2,把列表生成式的[]换成():

# 列表生成式
lis = [x*x for x in range(10)]
print(lis)

# 生成器
generator_ex = (x*x for x in range(10))
print(generator_ex)
 
结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x000002A4CBF9EBA0>

用yield实现“在单线程的情况下实现并发运算的效果”:

import time
def consumer(name):
    print("%s 准备学习啦!" %name)
    while True:
       lesson = yield  # 没有send()时候,此处返回None;send()之后,此处返回send()过来的数值
       print("开始[%s]了,[%s]老师来讲课了!" %(lesson,name))
 
 
def producer():
    c = consumer('A')
    c2 = consumer('B')
    c.next()
    c2.next()
    print("同学们开始上课 了!")
    for i in range(10):
        time.sleep(1)
        print("到了两个同学!")
        c.send(i)   # 把一个值发送到yield后面
        c2.send(i)
 
producer()


结果:
A 准备学习啦!
B 准备学习啦!
同学们开始上课 了!
到了两个同学!
开始[0]了,[A]老师来讲课了!
开始[0]了,[B]老师来讲课了!
到了两个同学!
开始[1]了,[A]老师来讲课了!
开始[1]了,[B]老师来讲课了!
到了两个同学!
开始[2]了,[A]老师来讲课了!
开始[2]了,[B]老师来讲课了!
到了两个同学!
开始[3]了,[A]老师来讲课了!
开始[3]了,[B]老师来讲课了!
到了两个同学!
开始[4]了,[A]老师来讲课了!
开始[4]了,[B]老师来讲课了!
到了两个同学!
开始[5]了,[A]老师来讲课了!
开始[5]了,[B]老师来讲课了!
到了两个同学!
开始[6]了,[A]老师来讲课了!
开始[6]了,[B]老师来讲课了!
到了两个同学!

可迭代、迭代器、生成器总结

  • 可直接作用于for循环的就是可迭代的
  • 可直接作用于next()的就是可迭代对象
  • 用yield的函数就是生成器,列表生成式的[]换成()也能得到生成器

杂:

  • 同样要完成迭代,使用生成器(for i in range(5))相对使用列表生成式[for i in range(5)]的好处:前者节省内存,后者生成的数据都在内存中,浪费内存。
  • c.next() 和 c.send(None) 作用相同,区别在于send可传递参数给yield表达式。(详细区别日后添加)
  • 第一次调用时,必须使用next()语句和send(None)之一,不能使用send发送一个非None的值,否则会出错,因为这时没有yield语句来接收这个值。
def consumer():
    r = 'here'
    while True:
        # 1.先执行等号右边,所以直到第一次跳出函数,也没有给n1赋值。
        # 2.yield r 相当于一个整体,赋值给它。
        n1 = yield r
        if not n1:
            return
        print n1
        r = '%d00 OK' % n1


def produce(c):
    aa = c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print n
        r1 = c.send(n)
        print r1
    c.close()


c = consumer()
produce(c)


结果:
1
1
100 OK
2
2
200 OK
3
3
300 OK
4
4
400 OK
5
5
500 OK

下面说明下send执行的顺序。

先记住,n1 = yield r 这行是从右往左执行的。当第一次send(None)(对应11行)时,启动生成器,从生成器函数的第一行代码开始执行,直到第一次执行完yield(对应第4行)后,跳出生成器函数。这个过程中,n1一直没有定义。

运行到send(1)时,进入生成器函数,此时,将yield r看做一个整体,赋值给它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值