迭代器和生成器

可迭代对象:

       可以被 for 循环都是可迭代的

  拥有__iter__方法  ----可迭代协议

  特点:惰性运算

  例如:range(),str,list,tuple,dict,set

迭代器Iterator:

  拥有__iter__方法和__next__方法     ---迭代器协议

  迭代器中的__next__()方法可以一个一个的获取值

  例如:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o

  迭代器的好处:

  从容器类型中一个一个的取值,会把所有的值都取到。且只能取一次
  节省内存空间
  迭代器并不会在内存中再占用一大块内存,
  而是随着循环 每次生成一个
  每次next每次给我一个

生成器Generator:

  本质:迭代器,所以拥有__iter__方法和__next__方法

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

使用生成器的优点:

1.延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。

# 生成器 —— 迭代器
# 生成器函数
# 含有yield关键字的函数都是生成器函数
# 生成器函数的特点
#调用之后函数内的代码不执行,返回生成器
#每从生成器中取一个值就会执行一段代码,遇见yield就停止。
#如何从生成器中取值:
# for :如果没有break会一直取直到取完
# next :每次只取一个
# send :不能用在第一个,取下一个值的时候给上个位置传一个新的值
# 数据类型强制转换 :会一次性把所有数据都读到内存里

#特点:
#调用函数的之后函数不执行,返回一个生成器
#每次调用next方法的时候会取到一个值
#直到取完最后一个,在执行next会报错

#生成器函数
# def generator():
#     print(1)
#     return 'a'
#
# ret = generator()
# print(ret)

#只要含有yield关键字的函数都是生成器函数
# yield不能和return共用且需要写在函数内
# def generator():
#     print(1)
#     yield 'a'
# #生成器函数 : 执行之后会得到一个生成器作为返回值
# ret = generator()
# print(ret)
# print(ret.__next__())

# def generator():
#     print(1)
#     yield 'a'
#     print(2)
#     yield 'b'
#     yield 'c'
# g = generator()
# for i in g:
#     print(i)
# ret = g.__next__()
# print(ret)
# ret = g.__next__()
# print(ret)
# ret = g.__next__()
# print(ret)

#娃哈哈%i
def wahaha():
    for i in range(2000000):
        yield '娃哈哈%s'%i
# g = wahaha()
# g1 = wahaha()
# print(g.__next__())
# print(g1.__next__())

# g = wahaha()
# count = 0
# for i in g:
#     count +=1
#     print(i)
#     if count > 50:
#         break
# # print('*******',g.__next__())
# for i in g:
#     count +=1
#     print(i)
#     if count > 100:
#         break
View Code

生成器表达式
# (条件成立想放在生成器中的值 for i in 可迭代的 if 条件)

监听列子

def jt(filename):
    f = open(filename,encoding='utf-8')
    while True:
        line = f.readline()
        if line.strip():
            yield line.strip()

g = jt('file')
for i in g:
    if 'python' in i:
        print('***',i)
View Code

send

send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一yield的位置传递一个数据
使用send的注意事项
第一次使用生成器的时候 是用next获取下一个值
最后一个yield不能接受外部的值

获取移动平均值

# avg = sum/count
# def average():
#     sum = 0
#     count = 0
#     avg = 0
#     while True:
#         num = yield avg
#         sum += num    # 10
#         count += 1    # 1
#         avg = sum/count
#
# avg_g = average()
# avg_g.__next__()
# avg1 = avg_g.send(10)
# avg1 = avg_g.send(20)
# print(avg1)
View Code

预激生成器的装饰器

# def init(func):   #装饰器
#     def inner(*args,**kwargs):
#         g = func(*args,**kwargs)    #g = average()
#         g.__next__()
#         return g
#     return inner
#
# @init
# def average():
#     sum = 0
#     count = 0
#     avg = 0
#     while True:
#         num = yield avg
#         sum += num    # 10
#         count += 1    # 1
#         avg = sum/count
#
# avg_g = average()   #===> inner
# ret = avg_g.send(10)
# print(ret)
# ret = avg_g.send(20)
# print(ret)
View Code

yield from

#python 3
# def generator():
#     a = 'abcde'
#     b = '12345'
#     for i in a:
#         yield i
#     for i in b:
#         yield i
# def generator():
#     a = 'abcde'
#     b = '12345'
#     yield from a
#     yield from b
#
# g = generator()
# for i in g:
#     print(i)
View Code

生成器表达式

#[每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] #遍历之后挨个处理
#[满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件] #筛选功能

生成器表达式
1. 
print([i*i for i in range(10)])
翻译如下

# g = (i for i in range(10))
# print(g)
# for i in  g:
#     print(i)
View Code
# #30以内所有能被3整除的数
# ret = [i for i in range(30) if i%3 == 0]  #完整的列表推导式
# g = (i for i in range(30) if i%3 == 0)  #完整的列表推导式
# print(ret)
#
# #30以内所有能被3整除的数的平方
# ret = [i*i for i in (1,2,3,4) if i%3 == 0]
# 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]
# ret = (name for lst in names for name in lst if name.count('e') ==2)
# print(ret)

#字典推导式


# 例一:将一个字典的key和value对调
# mcase = {'a': 10, 'b': 34}
# #{10:'a' , 34:'b'}
# mcase_frequency = {mcase[k]: k for k in mcase}
# print(mcase_frequency)

# 例二:合并大小写对应的value值,将k统一成小写
# mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
# #{'a':10+7,'b':34,'z':3}
# mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase}
# print(mcase_frequency)

#集合推导式,自带结果去重功能
# squared = {x**2 for x in [1, -1, 2]}
# print(squared)
View Code
# 3.处理文件,用户指定要查找的文件和内容,将文件中包含要查找内容的每一行都输出到屏幕
# def check_file(filename,aim):
#     with open(filename,encoding='utf-8') as f:   #句柄 : handler,文件操作符,文件句柄
#         for i in f:
#             if aim in i:
#                 yield i
#
# g = check_file('1.复习.py','生成器')
# for i in g:
#     print(i.strip())

# 4.写生成器,从文件中读取内容,在每一次读取到的内容之前加上‘***’之后再返回给用户。
# def check_file(filename):
#     with open(filename,encoding='utf-8') as f:   #句柄 : handler,文件操作符,文件句柄
#         for i in f:
#             yield '***'+i
#
# for i in check_file('1.复习.py'):
#     print(i.strip())
View Code
def add(n, i):
    return n+i

def test():
    for i in range(4):
        yield i
g = test()                        
for n in [1,10,5]:                 #  n = 1
    g =(add(n, i) for i in g)      #  g =  add(n, i) for i in g   # 其中 g = test() 如下
        #分解for循环     >>>       #  g =  add(n, i) for i in test()
                                   #  n = 10
                                   #  g = add(n, i) for i in g # 其中 g = add(n, i) for i in test() 如下
                                   #  g = add(n, i) for i in add(n, i) for i in test()
                                   #  n = 5
                                   #  g = add(n, i) for i in g #  其中 g =add(n, i) for i in add(n, i) for i in test()如下
                                   #  g = add(n, i) for i in add(n, i) for i in add(n, i) for i in test()
#解  n = 5
# g = add(n, i) for i in add(n, i) for i in add(n, i) for i in test()
#test() = (0,1,2,3)
#g = add(n, i) for i in add(n, i) for i in add(n, i) for i in (0,1,2,3)
#g = add(n, i) for i in add(n, i)for i in (5,6,7,8)
#g = add(n, i) for i in (10,11,12,13)
#g = (15,16,17,18)
print(list(g))






def demo():
    for i in range(4):
        yield i

g = demo()

g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g))  # g = demo() -> g 是生成器,list强转 list(g) = [0,1,2,3] g已经把生成器的值都取完了,生成器的特点,只能取一次值
                   #   所以后面的再取值 就是一个空的列表了,已经没有值了
print(list(g1))  
print(list(g2))
View Code
原文地址:https://www.cnblogs.com/bzluren/p/10645985.html