python notice9 迭代器和生产器

一、迭代器

  可以进行for循环的都是可迭代对象,常见的可迭代对象:str、list、tuple、dict、set、range、f(文件),它们都遵循可迭代协议。  

s = "小黑人"
for el in s:
    print(el)

  Iterable:可迭代对象,内部包含__iter__()函数。

  Iterator:迭代器,内部包含__iter__同时还包含__next__()。

  想要查看某数据类型是否为可迭代对象或者迭代器,可以通过dir()函数查看时候包含__iter__或者__iter__和__next()__。

  通过__iter__()可以获取到对象的迭代器,使用迭代器中的__next__()来获取迭代器中的元素。

s = "小黑人"
c = s.__iter__()    #获取迭代器
print(c.__next__())    #使用迭代器进行迭代,获取一个元素,小
print(c.__next__())    #
print(c.__next__())    #
print(c.__next__())    #StopIteration

  迭代器特点:

    1.节省内存。

    2.惰性机制。

    3.只能向下执行,不能反复。

补充:for循环机制

s = "小黑人"
c = s.__iter__()
while True:
    try:
        i = c.__next__()
        print(i)
    except StopIteration:
        break

 二、生成器

  生成器实质就是迭代器。获取生成器有三种方法:生成器函数、推导式获取生成器、通过数据转换获取生成器。

1.生成器函数

def func():
    print("小黑人")
    yield 114    #把函数中return改成yield,这个函数就是生成器函数
    print("小黑人不黑")
    yield 3114    #原来时0114,但是会报错,0不能打头,语法不支持。
ret = func()
print(ret)
ss = ret.__next__()
print(ss)
ss = ret.__next__()
print(ss)
结果:<generator object func at 0x0000027203D4A2A0>
        小黑人
        114
     小黑人不黑
     3114

  注:执行这个函数时,就不是函数的执行,而是获取这个生成器。生成器本质时迭代器,可以通过__next__()来执行生成器。

  yield和return效果一样,遇到return是直接停止执行函数,而yield是分段来执行一个函数(当内容多时,一次性全部输出,会占大量内存;而用yield时,next一此就输出一个,不占内存)。当程序运行完最后一个yield,后面继续进行__next__()时程序会报错。

  生成器也可以用for循环获取内部元素。因为生成器就是迭代器,迭代器为可迭代对象,故可以进行for循环。 

补充send:

  1.send()和__next__()一样,都可以让生成器执行到下一个yield;

  2.send可以给上一个yield的位置传递值,但不能给最后一个yield传值,同时在第一次执行生成器代码时不能使用send()。

def func():
    print("小黑人")
    a = yield 114    #把函数中return改成yield,这个函数就是生成器函数
    print("a=",a)
    yield 3114    #原来时0114,但是会报错,0不能打头,语法不支持。
ret = func()
ss = ret.__next__()
print(ss)
ss = ret.send("小黑人不黑")
print(ss)

结果:
小黑人
114
a= 小黑人不黑
3114

 2.生成器表达式

  列表、字典、集合都有推导式,元组没有推导式。

  列表推导式:[结果 fof 变量 in 可迭代对象 if 筛选]

  字典推导式:{结果 fof 变量 in 可迭代对象 if 筛选}  结果:key:value

  集合推导式:{结果 fof 变量 in 可迭代对象 if 筛选}  结果:key

  eg:列表推导式:list = [结果 for in 可迭代对象 if 条件]

lst = ["小黑人%s" % i for i in range3)]
print(lst)
结果:
['小黑人0', '小黑人1', '小黑人2']

  列表推导式代码简单,但是出现错误之后不易排查。

  生成器表达式和列表推导式语法一样,只是把[]换成()。

lst =("小黑人%s" % i for i in range(0))
print(lst)
结果:
<generator object <genexpr> at 0x0000017602B9A2A0>

  生成器表达式和列表推导式区别:

    1.列表推导式比较耗内存,一次性加载,生成器表达式几乎不占内存,使用时才分配和使用内存。

    2.得到的值不一样。列表推导式得到的是一个列表,生成器表达式获取的是一个生成器。

  注:生成器有惰性机制:生成器只有在方位的时候才有值。说白了,找它要才会给值,不找它要,它是不会执行的。

def func():
    print(111)
    yield 222

g = func()    #生成器g
g1 = (for i in g)    #生成器g1,但是g1的数据来源于g
g2 = for i in g1)    #生成器g2,但是g2的数据来源于g1

print(list(g))    #获取g中的数据,这时func()才会被执行,打印111,获取222,g完毕
print(list(g1))    #获取g1中的数据,g1的数据来源是g,但g已经取完,没有数据了。
print(list(g2))    #和g1相同

 

测试题

def add(a,b):
    return a + b

def test():
    for r_i in range(4):
        yield r_i

g = test()

for n in [2,10]:
    g = (add(n,i) for i in g)  
'''
展开一层:g = (add(n,i) for i in add(n,i) for i in g),
展开第二层:g = (add(n,i) for i in add(n,i) for i in test()),
两个n在取值时不可能不同,取值时为10。
'''

print(g)
print(list(g))    #惰性机制,不到最后不会拿值。
    
结果:
<generator object <genexpr> at 0x000001C5C0C6A408>
[20, 21, 22, 23]

 

 

  

  

posted @ 2019-07-27 15:14  小路_fan  阅读(223)  评论(0编辑  收藏  举报