python 学习:迭代器,生成器

"""
迭代器(iterator)提供了一个 next 的方法。调用这个方法后,你要么得到这
个容器的下一个对象,要么得到一个 StopIteration 的错误(苹果卖完了)。你不需要像列
表一样指定元素的索引,因为字典和集合这样的容器并没有索引一说。比如,字典采用哈希
表实现,那么你就只需要知道,next 函数可以不重复不遗漏地一个一个拿到所有元素即
可。
而可迭代对象,通过 iter() 函数返回一个迭代器,再通过 next() 函数就可以实现遍历。for
in 语句将这个过程隐式化,所以,你只需要知道它大概做了什么就行了

生成器是懒人版本的迭代器
我们知道,在迭代器中,如果我们想要枚举它的元素,这些元素需要事先生成
生成器,在你调用 next() 函数的时候,才会生成下一个变量。生成
器在 Python 的写法是用小括号括起来,(i for i in range(100000000)),即初始
化了一个生成器。
生成器并不会像迭代器一样占用大量内存,只有在被使用的
时候才会调用。而且生成器在初始化的时候,并不需要运行一次生成操作
"""


def is_iterable(param):
    try:
        iter(param)
        return True
    except TypeError:
        return False


params = [
    1234,
    '1234',
    [1, 2, 3, 4],
    set([1, 2, 3, 4]),
    {1: 1, 2: 2, 3: 3, 4: 4},
    (1, 2, 3, 4)
]
for param in params:
    print('{} is iterable? {}'.format(param, is_iterable(param)))


"""
yield 是魔术的关键。对于初学者来说,你可以理解为,函数运行到这一行的时
候,程序会从这里暂停,然后跳出,不过跳到哪里呢?答案是 next() 函数。那么 i ** k
是干什么的呢?它其实成了 next() 函数的返回值。
这样,每次 next(gen) 函数被调用的时候,暂停的程序就又复活了,从 yield 这里向下继
续执行;同时注意,局部变量 i 并没有被清除掉,而是会继续累加。我们可以看到 next_1
从 1 变到 8,next_3 从 1 变到 512
"""


def generator(k):
    i = 1
    while True:
        yield i ** k
        i += 1


gen_1 = generator(1)
gen_3 = generator(3)


def get_sum(n):
    sum_1, sum_3 = 0, 0
    for i in range(n):
        next_1 = next(gen_1)
        next_3 = next(gen_3)
        print(f'next_1 = {next_1}, next_3 = {next_3}')
        sum_1 += next_1
        sum_3 += next_3
    print(sum_1 * sum_1, sum_3)


get_sum(8)


def index_normal(source_list, target):
    """
    普通方法实现列表中找对应数的位置
    :param source_list:
    :param target:
    :return:
    """
    result = []
    for i, num in enumerate(source_list):
        if num == target:
            result.append(i)
    return result


print(index_normal([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2))


def index_generator(source_list, target):
    """
    生成器方法实现列表中找对应数的位置
    :param source_list:
    :param target:
    :return:
    """
    for i, num in enumerate(source_list):
        if num == target:
            yield i


print(list(index_generator([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2)))


def is_subsequence(child_list, father_list):
    # 转换成迭代器,可以利用next()可以保存指针位置的特性,从而确保子序列中元素的顺序
    father_list = iter(father_list)  # 得到迭代器
    return all(i in father_list for i in child_list)  # 所有的都是True 返回True,否则返回False


print(is_subsequence([1, 3, 5], [1, 2, 3, 4, 5]))
print(is_subsequence([1, 4, 3], [1, 2, 3, 4, 5]))

"""
i in b 等价于:
while True:
    val = next(b)
    if val == i:
        yield True
"""
b = (i for i in range(5))

print(2 in b)  # True
print(4 in b)  # True
print(3 in b)  # False
"""
容器是可迭代对象,可迭代对象调用 iter() 函数,可以得到一个迭代器。迭代器可以通
过 next() 函数来得到下一个元素,从而支持遍历。
生成器是一种特殊的迭代器(注意这个逻辑关系反之不成立)。使用生成器,你可以写
出来更加清晰的代码;合理使用生成器,可以降低内存占用、优化程序结构、提高程序
速度。
生成器只能遍历一次,继续调用 next() 会 raise StopIteration。只有复位生
成器才能重新进行遍历
"""
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容