迭代器和生成器

迭代器实现

# for 循环遍历列表、元组和字典等,这些对象都是可迭代的,因此它们都属于迭代器
'''__iter__(self):该方法返回一个迭代器(iterator),迭代器必须包含一个__next__()方法,
该方法返回迭代器的下一个元素。''' 

"""__reversed__(self):该方法主要为内建的 reversed() 反转函数提供支持,
当程序调用 reversed() 函数对指定迭代器执行反转时,实际上是由该方法实现的。"""

# 定义一个代表斐波那契数列的迭代器
class Fibs:
    def __init__(self, len):
        self.first = 0
        self.sec = 1
        self.__len = len
    # 定义迭代器所需的__next__方法
    def __next__(self):
        # 如果__len__属性为0,结束迭代
        if self.__len == 0:
            raise StopIteration
        # 完成数列计算:
        self.first, self.sec = self.sec, self.first + self.sec
        # 数列长度减1
        self.__len -= 1
        return self.first
    # 定义__iter__方法,该方法返回迭代器
    def __iter__(self):
        return self
# 创建Fibs对象
fibs = Fibs(10)
# 获取迭代器的下一个元素
print(next(fibs))
# 使用for循环遍历迭代器
for el in fibs:
    print(el, end=' ')


# 将列表转换为迭代器
my_iter = iter([3,4,5,'java'])

# 依次获取迭代器的下一个元素
print(my_iter.__next__()) # 3
print(my_iter.__next__()) # 4

生成器

# 创建生成器需要两步操作:
# 1.定义一个包含 yield 语句的函数。
# 2.调用第 1 步创建的函数得到生成器
def test(val, step):
    print("--------函数开始执行------")
    cur = 0
    # 遍历0~val
    for i in range(val):
        # cur添加i*step
        cur += i * step
        # print(cur,end=' ')
        yield cur

# yield cur 语句的作用有两点:
#    每次返回一个值,有点类似于 return 语句。
#    冻结执行,程序每次执行到 yield 语句时就会被暂停。

"""在程序被 yield 语句冻结之后,当程序再次调用 next() 函数获取生成器的下一个值时,
程序才会继续向下执行。"""
"""需要指出的是,调用包含 yield 语句的函数并不会立即执行,它只是返回一个生成器。
只有当程序通过 next() 函数调用生成器或遍历生成器时,函数才会真正执行。"""

# 执行函数,返回生成器
t = test(10, 2)
print('=================')
# 获取生成器的第一个值
print(next(t)) # 0,生成器“冻结”在yield处
print(next(t)) # 2,生成器再次“冻结”在yield处

"""从上面的输出结果不难看出,当程序执行 t = test(10, 2) 调用函数时,
程序并未开始执行 test() 函数;当程序第一次调用 next(t) 时,test() 函数才开始执行。
Python 2.x 不使用 next() 函数来获取生成器的下一个值,而是直接调用生成器的 next() 方法。
也就是说,在 Python 2.x 中应该写成 t.next()。

当程序调用 next(t) 时,生成器会返回 yield cur 语句返回的值(第一次返回 0),
程序被“冻结”在 yield 语句处,因此可以看到上面生成器第一次输出的值为 0。

当程序第二次调用 next(t) 时,程序的“冻结”被解除,继续向下执行,这一次循环计数器 i 变成 1,
在执行 cur += i * step 之后,cur 变成 2 ,
生成器再次返回 yield cur 语句返回的值(这一次返回 2),
程序再次被“冻结”在该 yield 语句处,因此可以看到上面生成器第二次输出的值为 2。
"""

# 由于前面两次调用 next() 函数已经获取了生成器的前两个值,因此此处循环时第一次输出的值就是 6
for x in t:
    print(x,end=' ')#6 12 20 30 42 56 72 90

print("***************************")
#再次创建生成器
t = test(10, 1)
#将生成器转换成列表
print (list (t))
#再次创建生成器
t = test(10, 3)
#将生成器转换成元组
print(tuple(t))


"""
使用生成器的优势:
1.当使用生成器来生成多个数据时,程序是按需获取数据的,它不会一开始就把所有数据都生成出来,
而是每次调用 next() 获取下一个数据时,生成器才会执行一次,因此可以减少代码的执行次数。
比如前面介绍的示例,程序不会一开始就把生成器函数中的循环都执行完成,
而是每次调用 next() 时才执行一次循环体。
2.当函数需要返回多个数据时,如果不使用生成器,程序就需要使用列表或元组来收集函数返回的多个值,
当函数要返回的数据量较大时,这些列表、元组会带来一定的内存开销。
如果使用生成器就不存在这个问题,生成器可以按需、逐个返回数据。
3.使用生成器的代码更加简洁。
"""

 

posted @ 2019-08-26 19:12  橘子先生123  阅读(180)  评论(0编辑  收藏  举报