Python迭代器与生成器实例演示

本文介绍了Python中迭代器和生成器的基本概念及高级应用,包括手动遍历、代理迭代、实现迭代器协议等,还讲解了如何使用生成器创建新迭代模式、实现反向迭代及迭代器切片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : Peidong
# @Site    : 
# @File    : iter_and_generate.py
# @Software: PyCharm

# 迭代器与生成器

# 1.1 手动遍历迭代器
# 使用next() 函数并在代码中捕获StopIteration 异常
items = [1, 2, 3, 4]
# 获取迭代
it = iter(items)
print(next(it)) #1
print(next(it)) # 2
print(next(it)) # 3
print(next(it)) # 4

# 1.2 代理迭代
# 问题:你构建了一个自定义容器对象,里面包含有列表、元组或其他可迭代对象。你想直
# 接在你的这个新容器对象上执行迭代操作。
# 解决:定义一个iter () 方法,将迭代操作代理到容器内部的对象上去。
class Node:
    def __init__(self, value):
        self.value = value
        self._children = []

    def __repr__(self):
        return 'Node{!r}'.format(self.value)

    def add_child(self, node):
        self._children.append(node)

    def __iter__(self):
        return iter(self._children)

# 使用实例
if __name__ == '__main__':
    root = Node(0)
    child1 = Node(1)
    child2 = Node(2)
    root.add_child(child1)
    root.add_child(child2)
    # 迭代遍历
    for ch in root:
        print(ch)

# 1.3 使用生成器创建新的迭代模式
def frange(start, stop, increment):
    x = start
    while x < stop:
        yield x
        x += increment
for n in frange(0, 4, 0.5):
    print(n)
print(list(frange(0, 4, 0.5)))
# 生成器智能用于迭代操作,一个生成器函数主要特征是它只会回应在迭代中使用到的next 操作。一旦生成器
# 函数返回退出,迭代终止。
def countdown(n):
    print('Starting to count from', n)
    while n > 0:
        yield n
        n -= 1
    print('Done!')

c = countdown(3)
print(c)
print(next(c)) # 3
print(next(c)) # 2
print(next(c)) # 1
print(next(c)) # Done

# 1.4 实现迭代器协议
# 在一个对象上实现迭代最简单的方式是使用一个生成器函数
class Node:
    def __init__(self, value):
        self.value = value
        self._children = []

    def __repr__(self):
        return 'Node{!r}'.format(self.value)

    def add_child(self, node):
        self._children.append(node)

    def __iter__(self):
        return iter(self._children)

    def depth_first(self):
        yield self
        for c in self:
            yield from c.depth_first()

# 实例
if __name__ == '__main__':
    root = Node(0)
    child1 = Node(1)
    child2 = Node(2)
    root.add_child(child1)
    root.add_child(child2)
    child1.add_child(Node(3))
    child1.add_child(Node(4))
    child2.add_child(Node(5))
    for ch in root.depth_first():
        print(ch)

# 1.4 反向迭代
# 使用内置的reversed()函数
a = [1, 2, 3, 4]
for x in reversed(a):
    print(x)
# 反向迭代仅仅当对象的大小可预先确定或者对象实现了reversed () 的特殊方
# 法时才能生效。如果两者都不符合,那你必须先将对象转换为一个列表才行
f = open('someFile')
for line in reversed(list(f)):
    print(line, end='')
在自定义类上实现__reversed__()方法来实现反向迭代
class Countdown:
    def __init__(self, start):
        self.start = start

    # Forward iterator
    def __iter__(self):
        n = self.start
        while n > 0:
            yield n
            n -= 1

    # Reverse iterator
        def __reversed__(self):
            n = 1
            while n <= self.start:
                yield n
                n += 1
for rr in Countdown(30):
    print(rr)

# 1.5 迭代器切片
# 函数itertools.islice() 正好适用于在迭代器和生成器上做切片操作
def count(n):
    while True:
        yield n # 生成器
        n += 1
c = count(0)

import itertools
for x in itertools.islice(c, 10, 20):
    print(x, end=' ')
# 迭代器和生成器不能使用标准的切片操作,因为它们的长度事先我们并不知道(并
# 且也没有实现索引)。函数islice() 返回一个可以生成指定元素的迭代器,它通过遍
# 历并丢弃直到切片开始索引位置的所有元素。然后才开始一个个的返回元素,并直到
# 切片结束索引位置。
# 这里要着重强调的一点是islice() 会消耗掉传入的迭代器中的数据。必须考虑到
# 迭代器是不可逆的这个事实。所以如果你需要之后再次访问这个迭代器的话,那你就
# 得先将它里面的数据放入一个列表中。

# 1.6 排列组合的迭代
# 迭代遍历一个集合中元素的所有可能的排列或组合
# itertools 模块提供了三个函数来解决这类问题。其中一个是
# itertools.permutations() , 它接受一个集合并产生一个元组序列, 每个元组
# 由集合中所有元素的一个可能排列组成
items = ['a', 'b', 'c']
from itertools import permutations
for p in permutations(items):
    print(p)
# 如果你想得到指定长度的所有排列,你可以传递一个可选的长度参数
for p in permutations(items, 2):
    print(p)
# 使用itertools.combinations() 可得到输入集合中元素的所有的组合
from itertools import combinations
for c in combinations(items, 3):
    print(c)
for c in combinations(items, 2):
    print(c)
for c in combinations(items, 1):
    print(c)
# 在计算组合的时候, 一旦元素被选取就会从候选中剔除掉(比如
# 如果元素’a’ 已经被选取了, 那么接下来就不会再考虑它了)。而函数
# itertools.combinations with replacement() 允许同一个元素被选择多次
for c in combinations_with_replacement(items, 3): # 命令有问题
    print(c)

# 1.7 序列上索引值迭代
# 问题:想在迭代一个序列的同时跟踪正在被处理的元素索引
# 解决:内置的enumerate() 函数可以很好的解决这个问题
my_list = ['a', 'b', 'c', 'd']
for idx, val in enumerate(my_list):
    print(idx, val, end=' ') # 0 a 1 b 2 c 3 d
# 为了按传统行号输出(行号从1 开始),你可以传递一个开始参数
for idx, val in enumerate(my_list, 1):
    print(idx, val, end=' ') # 1 a 2 b 3 c 4 d

# 1.8 同时迭代多个序列
# 同时迭代多个序列,每次分别从一个序列中取一个元素
# 解决:同时迭代多个序列,使用zip() 函数
xpts = [1, 5, 4, 2, 10, 7]
ypts = [101, 78, 37, 15, 62, 99, 100, 123]
for x, y in zip(xpts, ypts):
    print(x, y)
# 迭代长度与参数中最短序列长度一致
# 如果这个不是你想要的效果,那么还可以使用itertools.zip longest() 函数来代替
from  itertools import zip_longest
for i in zip_longest(xpts, ypts):
    print(i, end=' ')
# 成对处理数据的时候zip() 函数是很有用的
headers = ['name', 'shares', 'price']
values = ['ACME', 100, 490.1]
# 使用zip() 可以让你将它们打包并生成一个字典
s = dict(zip(headers,values))
print(s)
# 成对输出
for name, val in zip(headers, values):
    print(name, '=', val)
# 多组数同时输出
a = [1, 2, 3]
b = [10, 11, 12]
c = ['x','y','z']
for i in zip(a, b, c):
    print(i)
# zip() 会创建一个迭代器来作为结果返回。如果你需要将结对的值存储在列表中,要使用list() 函数

# 1.9 不同集合上元素的迭代
# 你想在多个对象执行相同的操作,但是这些对象在不同的容器中,你希望代码在不
# 失可读性的情况下避免写重复的循环。
# itertools.chain() 方法可以用来简化这个任务
from itertools import chain
a = [1, 2, 3, 4]
b = ['x', 'y', 'z']
for x in chain(a, b):
    print(x)

# 1.10 展开嵌套的序列
from collections import Iterable
def flatten(items, ingore_types = (str, bytes)):
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, ingore_types):
            yield from flatten(x)
        else:
            yield x
items = [1, 2, [3, 4, [5, 6], 7], 8]
for x in flatten(items):
    print(x, end=' ') # 1 2 3 4 5 6 7 8
# 在上面代码中, isinstance(x, Iterable) 检查某个元素是否是可迭代的。如果是的话
# , yield from 就会返回所有子例程的值
# 额外的参数ignore types 和检测语句isinstance(x, ignore types) 用来将字符
# 串和字节排除在可迭代对象外,防止将它们再展开成单个的字符
items = ['Dave', 'Paula', ['Thomas', 'Lewis']]
for x in flatten(items):
    print(x)

# 1.11 顺序迭代合并后的排序迭代对象
# 问题:你有一系列排序序列,想将它们合并后得到一个排序序列并在上面迭代遍历。
# 解决:heapq.merge() 函数可以帮你解决这个问题
import heapq
a = [1, 4, 7, 10]
b = [2, 5, 10, 13]
for c in heapq.merge(a, b):
    print(c)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值