python基础 迭代器

列表生成式:

a=[1,2,3]
print a
b=[i*2 for i in range(10)]    #i循环10次,每一个i的值乘2就是列表中的值。列表生成式
print b
>>[1, 2, 3]
>>[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

 生成器:

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

b=(i*2 for i in range(10))  #将生成列表中的[]转换成(),就是一个生成器。
print b

 生成器与列表的区别:

列表在定义的时候,已经在内存中开辟一定空间,而生成器只有在访问元素时才会在内存中开辟空间。

a=[1,2,3]     #列表
print a
b=(i*2 for i in range(10))    #生成器
print b  
>>[1, 2, 3]      #内存中的值
>><generator object <genexpr> at 0x025048C8>    #内存地址
b=(i*2 for i in range(10)) 
for i in b:       #生成器只有在访问元素时才会在内存中开辟空间
  print i
print b
0
2
4
6
8
10
12
14
16
18
<generator object <genexpr> at 0x02154AF8>

 

注:生成器不能通过像使用列表那样去使用切片、通过索引访问元素值。

只能通过for循环一个个的取值(只有在调用时才会生成相应的数据),生成器只记住当前的位置,当前的值,前面已经输出的值,生成器不会记得,只有一个_next_()方法3.0,2.7next()

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'
fib(10)

1
1
2
3
5
8
13
21
34
55
done

  

def fib(max):
    n,a,b = 0,0,1

    while n < max:
        #print(b)
        yield  b     '''上面的函数和generator仅一步之遥。要把fib函数变成generator, 只需要把print(b)改为yield b ,yidld 也有return的作用'''
        a,b = b,a+b
        n += 1
    return 'done' 
 f = fib(6)
 f
data = fib(10)
print(data)
print(data.__next__())
print(data.__next__())
print("ss")
print(data.__next__())
print(data.__next__())
print(data.__next__())
>><generator object fib at 0x104feaaa0>
>><generator object fib at 0x101be02b0>
>>1
>>1
>>ss
>>2
>>3
>>5

还可通过yield实现在单线程的情况下实现并发运算的效果(准确说是协程)

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    print c          
    c.next()       #这里的c指的是在内存中存放A的内存地址    0x02265490
    c2.next()
    print("老子开始准备做包子啦!")
    for i in range(5):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i)
        c2.send(i)
producer("小明")

<generator object consumer at 0x021D5490>
A 准备吃包子啦!
B 准备吃包子啦!
老子开始准备做包子啦!
做了2个包子!
包子[0]来了,被[A]吃了!
包子[0]来了,被[B]吃了!
做了2个包子!
包子[1]来了,被[A]吃了!
包子[1]来了,被[B]吃了!
做了2个包子!
包子[2]来了,被[A]吃了!
包子[2]来了,被[B]吃了!
做了2个包子!
包子[3]来了,被[A]吃了!
包子[3]来了,被[B]吃了!
做了2个包子!
包子[4]来了,被[A]吃了!
包子[4]来了,被[B]吃了!

yield 返回当前函数在内存中的地址,

next(),回到yield的执行位置,没有传值的作用。

send(b1) 回到yield的执行位置,可以传值给yield。

 迭代器

迭代,顾名思义就是重复做一些事很多次,迭代器是实现了__next__()方法的对象。

能for循环的对象统称为可迭代对象:Iterable,可以使用isinstance()判断一个对象是否是Iterable对象:

from collections import Iteable
isinstance([],Iterable)

true

可以被next()调用并不断返回下一个值的对象成为迭代器Iterator,查看对象是否是迭代器使用dir()查看是否用next()函数。

生成器就是一个迭代器,

判断是不是一个迭代器:

from collections import Iterator
isinstance((i for i in range(5)),Iterator)
true

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

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

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

  

  

 

 

 

猜你喜欢

转载自www.cnblogs.com/iexperience/p/9053918.html