函数四--迭代器和生成器

一、迭代器

  迭代器协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么引起一个StopIteration异常,以终止迭代(只能往后走,不能往前走)。

  实现了迭代器协议的对象(对象内部定义了一个__iter__()方法)

  python中的内部工具(如for循环,sum,min,max函数等)都是基于迭代器协议访问对象

  只要含有__iter__方法的都是可迭代的-----可迭代协议;迭代器协议:内部含有__next__和__iter__方法的就是迭代器

  只要是迭代器就一定可迭代; 可迭代的.__iter__()方法就可以得到一个迭代器; 迭代器中的__next__()方法可以一个一个的获取值。

  当我们遇到一个新的变量,不确定能不能for循环的时候,就判断它是否可迭代,因为只有是可迭代对象的时候才能用for

  迭代器的好处:

    1:从容器类型中一个一个的取值,会把所有的值都取到

    2:节省内存空间(range,文件句柄f)

  迭代器并不会在内存中占用一大块内存,而是随着循环,每次生成一个,通过每次next会每次给我一个

li = [1,2,3]
#基于迭代器协议
iterator = li.__iter__()
print(iterator.__next__())  # 1
print(iterator.__next__())  # 2
print(iterator.__next__())  # 3
# print(iterator.__next__())  #超出边界报错

#下标
print(li[0]) # 1
print(li[1]) # 2
print(li[2]) # 3
print(li[3]) # 超出边界报错
#用while循环模拟for循环机制
li = [1,2,3]
iterator = li.__iter__()
while True:
    try:
        print(iterator.__next__())
    except StopIteration:
        print('迭代完毕,循环终止')
        break

# for循环访问方式
# for循环本质就是遵循迭代器协议的访问方式,先调用iterator = li.__iter__()方法,
# 然后依次执行iterator.__next__(),直到捕捉到 StopItearation终止循环
# for循环所有的对象的本质都是一样的原理
View Code

二、生成器   ---本质就是迭代器

  在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行

  表现形式

    1、生成器函数   带yield的函数(a.返回值     b.保留函数的运行状态)

      next(t)      t.__next__()      t.send()

#用生成器函数
#yield相当于return控制的是函数的返回值
#x=yield的另外一种特性,接收send传过来的值,赋值给x
def test():
    print("begin")
    first = yield # return 1   first = None
    print("111",first)
    yield 2
    print("222")
t = test()
print(test().__next__())
res = t.__next__() # next(t)
print(res)
res = t.send("函数停留在first那个位置,我就是给first赋值的")
print(res)

'''
输出结果:
    begin
    None
    begin
    None
    111 函数停留在first那个位置,我就是给first赋值的
    2
'''

    2、生成器表达式

g = (i for i in range(10))
# print(g)
for i in g:
    print(i)

     各种推导式

# [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型]    #有点像遍历之后挨个处理
# [满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件]   #筛选功能
ret = [i for i in range(30) if i % 3 == 0]
print(ret)
ret = [i * i  for i in range(30) if i % 3 == 0]
print(ret)
# 找到嵌套列表中名字含有两个‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
ret = [name for lst in names for name in lst if name.count('e') == 2]
print(ret)
# dic = {'a':10,'b':34}
# dic1 = {dic[k]:k for k in dic}
# print(dic1)

#各种推导式:生成器、列表、字典、集合
    #遍历操作
    #筛选操作

#生成器中的数据只能取一次,取完就没有了
#惰性运算,不找它取值,它就不工作
#生成器表达式和列表推导式的区别:
#括号不一样
#返回的值不一样 :生成器几乎不占用内存

 

posted @ 2018-01-03 17:33  笨笨侠  阅读(157)  评论(0编辑  收藏  举报