Iterator

Reason is the light and the light of life.

Jerry Su Jun 11, 2020 1 mins

Iterator

iterator

iter(): 接收的是可迭代对象,返回的是迭代器。

next(): 接收的是迭代器,调用的是迭代器对象中的next函数,返回数据元素。

由于生成器是一种特殊的迭代器,故而用next()而不是iter()。

class Classmate(object):
    def __init__(self):
        self.names = list()

    def add(self, name):
        self.names.append(name)

    def __iter__(self):
        # 返回迭代器对象
        return ClassIterator(self)

class ClassIterator(object):
    def __init__(self, obj):
        self.obj = obj
        self.cur = 0

    # 包含__iter__的方法对象成可迭代iterable
    def __iter__(self):
        pass

    # 包含__next__的方法对象成迭代器iterator
    def __next__(self):
        if self.cur < len(self.obj.names):
            res = self.obj.names[self.cur]
            self.cur += 1
            return res
        else:
            raise StopIteration

优化:去除迭代器ClassIterator,将Classmate写成迭代器,返回自身self即可。

from collections import Iterable
import time

class Classmate(object):
    def __init__(self):
        self.names = list()
        self.cur = 0

    def add(self, name):
        self.names.append(name)

    def __iter__(self):
        return self

    def __next__(self):
        if self.cur < len(self.names):
            res = self.names[self.cur]
            self.cur += 1
            return res
        else:
            raise StopIteration


if __name__ == '__main__':
    classmate = Classmate()
    classmate.add('Jerry')
    classmate.add('Annie')
    classmate.add('Sophie')
    print('Iterable: {}'.format(isinstance(classmate, Iterable)))

    for temp in classmate:
        print(temp)
        time.sleep(1)

Fibonacci数列,迭代器定义生成数据的方法,在访问的时候产生数据,节省内存。

class Fibonacci(object):
    def __init__(self, num):
        self.num = num
        self.cur = 0
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.cur < self.num:
            res = self.a
            self.a, self.b = self.b, self.a + self.b
            self.cur += 1
            return res
        else:
            raise StopIteration


if __name__ == '__main__':
    fibo = Fibonacci(10)
    for num in fibo:
        print(num)

Generator

生成器是特殊的迭代器。含有yield关键字的函数,不再是函数而是生成器。调用时不再是函数调用而是创建生成器对象。

yield关键字,将函数暂停,当下次访问时,接着yield后面继续执行。

生成器两种启动方式:next(generator)和generator.send(),后者可以传参。

生成器传参:generator.send(‘pass args’)

生成器return:在迭代结束抛出异常StopIterator时,返回return的内容。

def generator(n):
    cur = 0
    a, b = 0, 1
    while cur < n:
        ret = yield a
        print('ret>>>', ret)
        a, b = b, a + b
        cur += 1

# 并非调用函数,而是创建生成器对象,使用next()函数执行生成器代码。
obj = generator(10)

# next()函数传递的是迭代器,而生成器是一种特殊的迭代器
ret = next(obj)
print(ret)

# 启动生成器时,参数传给yield右边ret
ret = obj.send('pass arg')
print(ret)

ret = next(obj)
print(ret)

结论:迭代器能节省内存空间,能实现循环;生成器能暂定类函数的运行,用send或者next继续执行。他们都是保存生成数据的代码。

生成器的另一个重要应用协程:实现多任务。

import time

def task1():
    while True:
        print('---1---')
        time.sleep(0.1)
        yield

def task2():
    while True:
        print('---2---')
        time.sleep(0.1)
        yield

def main():
    t1 = task1()
    t2 = task2()
    while True:
        next(t1)
        next(t2)

if __name__ == '__main__':
    main()

Coroutine

采用同步的方式编写异步代码,线程的切换是操作系统执行的。单线程内的协程是程序员自己调度切换的。不需要锁的机制,函数的切换资源消耗更少,并发性更高。

协程:可以暂停的函数(生成器),且可以向暂停处传参。python通过生成器实现协程。


Read more:

Related posts: