'''
迭代器

迭代是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

可迭代对象
我们已经知道可以对list、tuple、str等类型的数据使用for...in...的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。

可以使用 isinstance() 判断一个对象是否是 Iterable 对象:
>>> from collections.abc import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance(mylist, Iterable)
False
>>> isinstance(100, Iterable)
False


简单来说,一个具备了__iter__方法的对象,就是一个可迭代对象。
class MyList(object):
     def __init__(self):
             self.container = []
     def add(self, item):
             self.container.append(item)
     def __iter__(self):
             """返回一个迭代器"""
             # 我们暂时忽略如何构造一个迭代器对象
             pass

>>> mylist = MyList()
>>> from collections import Iterable
>>> isinstance(mylist, Iterable)
True


iter()函数与next()函数
list、tuple、str、set、dict都是可迭代对象,我们可以通过iter()函数获取这些可迭代对象的迭代器。
然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。
iter()函数实际上就是调用了可迭代对象的__iter__方法。

>>> li = [11, 22, 33, 44, 55]
>>> li_iter = iter(li)
>>> next(li_iter)
11
>>> next(li_iter)
22
>>> next(li_iter)
33
>>> next(li_iter)
44
>>> next(li_iter)
55
>>> next(li_iter)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration


'''


class MyList():
    def __init__(self):
        self.items = []
    
    def add(self, val):
        self.items.append(val)

    def __iter__(self):
        return MyIterator(self)

class MyIterator(object):
    '''自定义供MyList使用的一个迭代器'''
    def __init__(self, mylist):
        self.list = mylist
        self.current = 0
    
    def __next__(self):
        if self.current < len(self.list.items):
            item = self.list.items[self.current]
            self.current += 1
            return item
        else:
            raise StopIteration

    def __iter__(self):
        return self



class FibIterator(object):
    '''斐波那契数列迭代器'''
    def __init__(self, n: int):
        '''
        :param n: int, 生成数列的前n个数
        '''
        self.n = n
        self.current = 0
        # 保存前前一个数,初始值为数列中的第一个数0
        self.num1 = 0
        # 保存前一个数,初始值为数列中的第二个数1
        self.num2 = 1

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            self.current += 1
            return num
        else:
            raise StopIteration
    
    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self


if __name__ == '__main__':
    # list = MyList()
    # list.add(1)
    # list.add(2)
    # list.add(3)
    # list.add(4)
    # list.add(5)

    # for n in list:
    #     print(n)

    fib = FibIterator(n=10)
    for n in fib:
        print(n)
    
    l = list(FibIterator(n=20))
    print(l)

    tp = tuple(FibIterator(n=15))
    print(tp)