欢迎第 位访客

Day 3-6 生成器&迭代器

---恢复内容开始---

列表生成式:

1 list = [i*i for i in range(20)]  # 这就是一个列表生成式
2 print(list)
3 # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]
4 list1 = [i if i < 8 else i*i  for i in range(10,20)]   # 可以进行三元运算.
5 print(list1)
6 # [110, 132, 156, 182, 210, 240, 272, 306, 342, 380]

 

生成器:在Python中,这种一边循环一边计算的机制,称为生成器:generator。

特性:

1.只能往后面生成,不能返回到原来的值

2.超过生成范围后,会停止生成,并报错。

生成器的创建方式:

1.通过列表生成式来创建   (i for i in range(100)

2.通过函数来创建.

a = [i for i in range(10000)]   # 列表生成式
a2 = (i for i in range(10000))      # 这个就是一个生成器.但是怎么取数据呢?
print(a2)                       # 我们print(a2),发现返回的是一个内存地址.那我们可以用next(a2)的方法来取数据.

# 以下代码是在交互模式下进行的

a2 = (i for i in range(1000))
next(a2)
0
next(a2)
1
next(a2)
2
next(a2)
3
a3 = (i for i in range(5))


next(a3)
4
next(a3)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
StopIteration

#我们手动调用的时候,调到最后一个的时候,再往下调就会出错.可以用for循环调用.就不会报错了
for i  in a3:
    print(i)

 python2中 range=list

    xrange = 生成器

python3 range =生成器

没有xrange  

 

 

 yield:

 yield 和 return区别:

yield  返回数据,并冻结当前的执行过程。

return 返回并终止函数。

当调用next的时候,唤醒冻结的函数执行过程。直到遇到下一次yield。

 

 函数有了yield之后:

1.函数名加()就就得到了生成器。

2.return 在生成器里,代表生成器终止,直接报错。 

def fblq(num):
    n, a, b = 0, 0, 1
    while n < num:
        print('我在yield之前.')
        yield b     #把函数的执行过程冻结在这一步,并把b返回给外面的next().
        print(b)
        a, b = b, a+b
        n +=1
    else:
        return 0


f = fblq(15)
next(f)
next(f)
next(f)
next(f)
# 有yield,函数调用时,不会执行。只是生成了一个生成器对象。


# 我在yield之前.
# 1
# 我在yield之前.
# 1
# 我在yield之前.
# 2
# 我在yield之前.

 

 1 # 函数的方式创建生成器
 2 
 3 def range1(n):
 4     count = 0
 5     while count <n:
 6         print(count)
 7         count +=1
 8         yield count   # 返回数据并冻结当前的执行状态.
 9 
10 
11 new = range1(10)
12 next(new)
13 next(new)
14 new.__next__() # 和next(new)一样

 

Send方法:

 1 def range1(n):
 2     count = 0
 3     while count <n:
 4         print(count)
 5         count +=1
 6         singe = yield count   # 返回数据并冻结当前的执行状态.
 7         if singe == "stop":   # 当接收的信号是stop时,就退出循环.
 8             break
 9 
10 new = range1(100)
11 
12 next(new)
13 next(new)
14 new.__next__()
15 new.send("stop")        #send 唤醒生成器继续执行并发送一个信号.next只唤醒生成器继续执行

 

迭代器:

可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

 

判断一个对象是否是一个可迭代对象:

from collections import Iterable
li = [1,2,3,4,5,6,7,8,9,0]
print(isinstance(li,Iterable))  # 判断一个对象是否是可迭代对象.是返回Trure,否返回False 

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

生成器可以用for和next来取值.可迭代对象只能用for进行迭代取值.

判断一个对象是否是Iterator对象:

from collections import Iterator

print(isinstance([],Iterator))  #  判断一个可迭代对象是不是一个迭代器
print(isinstance((i for i in range(100)), Iterator))  #  目前只有生成器是迭代器.迭代器的一个重要的标志就是可以next

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

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

from collections import Iterator

print(isinstance(iter([]),Iterator))  #  判断一个可迭代对象是不是一个迭代器
print(isinstance(iter("adfc"), Iterator))

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

 

posted @ 2018-04-02 20:21  大橡皮  阅读(100)  评论(0编辑  收藏  举报