# 可迭代对象:
    # 类型中申明了一个__iter__方法,同时该方法返回一个迭代器对象
    # 能够用for循环的都是可迭代对象
    # 列表、元组、字典、集合都是可迭代对象

# 迭代器:
    # 类型中申明了一个__next__方法

# for循环原理
    # (1) 调用 in 后面对象的__iter__方法,获得一个迭代器对象iter
    # (2) 不断的调用迭代器对象iter的__next__方法将返回值赋值给给变量i,知道收到StopIteration退出循环

from typing import Counter


l = [1,2,3]
iter = l.__iter__()
print(iter.__next__())  # 1
print(iter.__next__())  # 2
print(iter.__next__())  # 3
#print(iter.__next__())  # 只有三个值,第四个报错:StopIteration

# 实现一个迭代器
l = [i for i in range(1,101)]
#print(l)
# 所有的数据都存在到列表内存中,若要存大量数据,内存不足
class MyIter(object):
    def __init__(self) -> None:
        self.n = 0
        self.max = 5
    
    def __iter__(self):
        return self

    def __next__(self):
        if self.n < self.max:
            self.n += 1
        else:
            raise StopIteration
        return self.n

obj = MyIter()
obj.__iter__()
obj.__next__()
print(obj.__next__())

for i in obj:
    print(i)

##################################################
# 可以拆开,将iter和next方法写在两个类里面
class Num5(object):
    def __iter__(self):
        return MyIter()

class MyIter(object):
    def __init__(self) -> None:
        self.n = 0
        self.max = 5

    def __next__(self):
        if self.n < self.max:
            self.n += 1
        else:
            raise StopIteration
        return self.n

obj = Num5()

for i in obj:
    print(i)
###############################################
# 生成器:
    # 生成器是一个特殊的迭代器

def getNum():
    print("*" * 20) 
    count = 0
    while count < 5:
        count += 1
        yield count

l = getNum()  # 创建生成器对象,这个时候发现print("*" * 20) 没有被执行
print(l.__next__())  # 这个时候将执行print("*" * 20)
print(l.__next__())
for i in l:
    print(i)

# 生成器表达式
gen = (i for i in range(1,11))
print(gen)
print(gen.__next__())
print(next(gen))
for i in gen:
    print(i)
###################################################
def add(s, x):
    return x + s
def gen():
    for i in range(4):
        yield i

base = gen()
for n in [1, 10]:
    base = (add(i, n) for i in base)
# 这个里面1是取不到的
# 由于n = 1的时候,还是一个迭代器对象,所以不会执行代码
# 只有当list(base)的时候才能调用n,所以n将会取值10
# 从而得到[20, 21, 22, 23]
print(list(base))