迭代器和生成器

迭代的概念:迭代就是可以被遍历的数据类型,也就是可以被一个一个取出来。

那么可迭代的类型有哪些?

from collections import Iterable
                             
l = [1,2,3,4]                
t = (1,2,3,4)                
d = {1:2,3:4}                
s = {1,2,3,4}                
                             
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(s,Iterable))
View Code

这里可以看出,元组,列表,字典,集合,包括字符串都是可迭代的。

1)为什么可以被迭代呢?

这就要说一下迭代的协议。

迭代的协议就是内部含有——lter——方法。

2)什么是迭代器?

print([1,2].__iter__())

结果
<list_iterator object at 0x1024784a8>
View Code

执行了list([1,2])的__iter__方法,我们好像得到了一个list_iterator,现在我们又得到了一个新名词

——iterator。

iterator的意思就是迭代器。

迭代器和可迭代的对面之间的区别就是在内容里面多了一个:__next__,这也是他们之间的最根本区别。

__next__:迭代器就是因为多了这个才可以一个个迭代(遍历),

l = [1,2,3,4]
l_iter = l.__iter__()
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
View Code

上路的可迭代对象如果遍历完,那么就会报错。有时候我们就有一些异常的办法把异常处理出去:

l = [1,2,3,4]
l_iter = l.__iter__()
while True:
    try:
        item = l_iter.__next__()
        print(item)
    except StopIteration:
        break
View Code

标准格式就是list.__next__(),这之前要看他是不是可迭代对象,如果不行就用__iter__()把他变成可迭代对象,然后在用next一个个遍历.

迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。

3)range()是迭代器吗?

from collections import  Iterator
print(isinstance(range(100000000),Iterator))  
print(isinstance(range(100),Iterator))
这里的isinstance是查看里面的值是什么数据类型,Iterator就是看看是不是迭代器。

4)迭代器有什么作用:最重要的一点就是可以节省内存空间。

 

Python中提供的生成器:

1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

 

生成器Generator:

 

  本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

 

  特点:惰性运算,开发者自定义

 

 

import time
def genrator_fun1():
    a = 1
    print('现在定义了a变量')
    yield a
    b = 2
    print('现在又定义了b变量')
    yield b

g1 = genrator_fun1()
print('g1 : ',g1)       #打印g1可以发现g1就是一个生成器
print('-'*20)   #我是华丽的分割线
print(next(g1))
time.sleep(1)   #sleep一秒看清执行过程
print(next(g1))

初识生成器函数
View Code

 

这里有一些注意:首先运行一次genrator_fun1()的话,只会显示他是一个生成器,不会显示别东西,只有当你调用next(genrator_fun1())的话,他才会运行,但是你掉一次next他就只会运行到第一个yield,就不会再运行,只有你一下子调用2个next的时候,他才会一下子运行2个,并且把值返回到genrator_fun 里,下面谁接收的话,就给谁,另外,每一次调用后,当你重新调用的时候,程序又会重新从第一个开始运行。
ps:如果yield后面带了东西,当你运行到那的时候才会取出来。

 

 

下面是一些例子:

import tima
def func():
    f=open(filename)
    f.seak(0,2)
    while True:
        line=f.readline()
        if not line:
            time.sleep(0.2)
            continue
        else:
            yield  line
l=func()
for line in l:
    print(line)
View Code
#初识生成器二

def produce():
    """生产衣服"""
    for i in range(2000000):
        yield "生产了第%s件衣服"%i

product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g:         #要一批衣服,比如5件
    print(i)
    num +=1
    if num == 5:
        break

#到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
#剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
View Code
#初识生成器二

def produce():
    """生产衣服"""
    for i in range(2000000):
        yield "生产了第%s件衣服"%i

product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g:         #要一批衣服,比如5件
    print(i)
    num +=1
    if num == 5:
        break

#到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
#剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
衣服生产
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total/count


g_avg = averager()
next(g_avg)
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))

计算移动平均值(1)
平均值的计算
def init(func):  #在调用被装饰生成器函数的时候首先用next激活生成器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)
        next(g)
        return g
    return inner

@init
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total/count


g_avg = averager()
# next(g_avg)   在装饰器中执行了next方法
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))
平均值带装饰器

下面是一个生成器yield   from 的一些应用

def gen1():
    for c in 'AB':
        yield c
    for i in range(3):
        yield i

print(list(gen1()))

def gen2():
    yield from 'AB'
    yield from range(3)

print(list(gen2()))
yield from

 

列表表达式和生成器表达式:

之间的差别:列表表达式占系统内存空间较多,生成器几乎不占内存。

list=[x  for x in range(10000) ]---列表表达式

list=(x  for x in range(10000))---生成器表达式

 

posted @ 2017-08-02 21:29  forjie  阅读(166)  评论(0编辑  收藏  举报