从零开始:Python语言进阶之迭代器

一、重新认识迭代与可迭代对象

1.1 什么是迭代

迭代是一种有序访问数据元素的方式,在Python编程中随处可见。最常见的迭代场景就是使用 for 循环,例如遍历列表中的元素:

python 复制代码
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

在上述代码中, for 循环依次从 fruits 列表中取出每个元素,并将其赋值给 fruit 变量,这个过程就是迭代。本质上,迭代就是逐个处理数据集合中元素的过程,除了 for 循环,像 while 循环结合索引、列表推导式、生成器表达式等操作,底层也都依赖迭代机制。

1.2 可迭代对象(Iterable)

可迭代对象是Python中能够被迭代的数据结构。判断一个对象是否为可迭代对象,除了使用 isinstance() 函数结合 collections.abc.Iterable 模块外,还可以通过尝试调用对象的 iter() 方法来判断。如果对象有 iter() 方法,那么它就是可迭代对象。

python 复制代码
from collections.abc import Iterable

# 使用isinstance判断
my_str = "hello"
print(isinstance(my_str, Iterable))  # 输出: True

# 通过尝试调用__iter__方法判断
try:
    iter(my_str)
    print("是可迭代对象")
except TypeError:
    print("不是可迭代对象")

Python中常见的可迭代对象包括:

① 序列类型:列表(list)、元组(tuple)、字符串(str)。列表是可变的有序集合,元组是不可变的有序集合,字符串则是字符的有序集合,它们都支持按顺序迭代。

python 复制代码
my_list = [1, 2, 3]
my_tuple = (4, 5, 6)
my_str = "abc"

for element in my_list:
    print(element)

for element in my_tuple:
    print(element)

for char in my_str:
    print(char)

② 映射类型:字典(dict)。字典迭代时默认遍历的是键(keys),也可以通过 values() 方法遍历值,通过 items() 方法同时遍历键值对。

python 复制代码
my_dict = {"name": "Alice", "age": 25}
for key in my_dict:
    print(key)

for value in my_dict.values():
    print(value)

for key, value in my_dict.items():
    print(key, value)

③ 集合类型:集合(set)、冻结集合(frozenset)。集合是无序不重复元素的集合,在迭代时虽然顺序不确定,但依然可以逐个访问元素。

python 复制代码
my_set = {1, 2, 3}
for element in my_set:
    print(element)

④ 文件对象:当打开一个文件后,文件对象也是可迭代的,可以逐行读取文件内容。

python 复制代码
with open("test.txt", "r") as file:
    for line in file:
        print(line.strip())

二、迭代器的核心概念与实现

2.1 迭代器的定义

迭代器是Python中实现了 iter() 和 next() 方法的对象。 iter() 方法必须返回迭代器自身,它的主要作用是在需要时将迭代器对象传递出去; next() 方法用于获取下一个元素,当没有更多元素可供返回时,必须引发 StopIteration 异常,以此来告知迭代过程结束。

2.2 迭代器的工作机制

以一个简单的自定义迭代器类为例,深入剖析迭代器的工作流程:

python 复制代码
class CounterIterator:
    def __init__(self, stop):
        self.current = 0
        self.stop = stop

    def __iter__(self):
        return self

    def __next__(self):
        if self.current >= self.stop:
            raise StopIteration
        result = self.current
        self.current += 1
        return result

当我们使用 for 循环遍历这个迭代器时:

  1. 首先执行 iter(counter) ,即调用 CounterIterator 类的 iter() 方法,由于 iter() 方法返回的是迭代器 自身( return self ),所以获取到了迭代器对象。
python 复制代码
counter = CounterIterator(5)
iterator_obj = iter(counter)
  1. 然后 for 循环不断调用 next(iterator_obj) ,也就是调用迭代器对象的 next() 方法。在 next() 方法中,先检查 self.current 是否达到了停止条件( self.current >= self.stop ),如果没有达到,就将当前的 self.current 值赋值给 result ,然后将 self.current 自增1,最后返回 result 。
python 复制代码
print(next(iterator_obj))  # 输出 0
print(next(iterator_obj))  # 输出 1
  1. 当 self.current 达到停止条件时, next() 方法引发 StopIteration 异常, for 循环检测到这个异常后,会自动结束循环。
python 复制代码
# 连续调用next,最后会引发StopIteration异常
try:
    for _ in range(6):
        print(next(iterator_obj))
except StopIteration:
    print("迭代结束")

三、Python内置迭代器工具详解

3.1 iter() 函数

iter() 函数是将可迭代对象转换为迭代器对象的关键工具。它有两种使用形式:

① 基本形式:直接传入可迭代对象,返回对应的迭代器。

python 复制代码
my_list = [10, 20, 30]
list_iterator = iter(my_list)
print(next(list_iterator))  # 输出: 10

② 带哨兵值的形式: iter(callable, sentinel) ,这种形式会不断调用 callable 对象,直到返回值等于 sentinel 时停止迭代。常用于从文件中读取数据,直到遇到特定的结束标识。

python 复制代码
def get_number():
    num = 1
    while True:
        yield num
        num += 1

number_generator = get_number()
# 迭代直到数字等于5
for element in iter(lambda: next(number_generator), 5):
    print(element)

3.2 next() 函数

next() 函数用于调用迭代器的 next() 方法,获取迭代器的下一个元素。它还可以接受第二个参数,作为默认返回值。当迭代器耗尽,且指定了默认返回值时, next() 函数不会引发 StopIteration 异常,而是返回默认值。

python 复制代码
my_list = [1, 2, 3]
my_iter = iter(my_list)
print(next(my_iter))  # 输出: 1
print(next(my_iter))  # 输出: 2
print(next(my_iter))  # 输出: 3
# 迭代器耗尽后,指定默认返回值
print(next(my_iter, "迭代结束"))  # 输出: 迭代结束

3.3 生成器(Generator)

生成器是一种语法糖形式的迭代器,使用更加简洁。它通过在函数中使用 yield 关键字来实现。当生成器函数被调用时,不会立即执行函数体,而是返回一个生成器对象。每次调用 next() 方法(或使用 for 循环迭代)时,函数从上次 yield 语句暂停的位置继续执行,直到遇到下一个 yield 语句或函数结束。

python 复制代码
def even_numbers_generator():
    num = 0
    while True:
        yield num
        num += 2

even_gen = even_numbers_generator()
print(next(even_gen))  # 输出: 0
print(next(even_gen))  # 输出: 2

此外,还有生成器表达式,它的语法和列表推导式类似,只是将方括号 [] 换成圆括号 () 。生成器表达式也是返回一个生成器对象,具有延迟计算的特性,相比列表推导式更节省内存。

python 复制代码
squared_generator = (x ** 2 for x in range(5))
for num in squared_generator:
    print(num)

四、基础应用场景与常见问题解析

4.1 基础应用场景

① 文件逐行处理:在处理大文件时,使用迭代器逐行读取文件内容,避免一次性将整个文件读入内存。

python 复制代码
with open("large_file.txt", "r") as file:
    for line in file:
        # 对每一行进行处理,例如统计行数、查找特定字符串等
        pass

② 自定义数据遍历:通过自定义迭代器类,实现对自定义数据结构的遍历。比如自定义一个链表类,通过迭代器实现对链表节点的遍历。

python 复制代码
class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None

    def add_node(self, value):
        new_node = Node(value)
        if not self.head:
            self.head = new_node
        else:
            current = self.head
            while current.next:
                current = current.next
            current.next = new_node

    def __iter__(self):
        current = self.head
        while current:
            yield current.value
            current = current.next

linked_list = LinkedList()
linked_list.add_node(1)
linked_list.add_node(2)
linked_list.add_node(3)

for element in linked_list:
    print(element)

4.2 常见问题与解决

① 迭代器重复使用问题:迭代器是一次性的,一旦迭代结束就无法再次迭代。如果需要重复迭代,必须重新创建迭代器对象。

python 复制代码
my_list = [1, 2, 3]
my_iter = iter(my_list)
for element in my_iter:
    print(element)
# 此时my_iter已耗尽,再次迭代无输出
for element in my_iter:
    print(element)

# 重新创建迭代器对象即可再次迭代
new_iter = iter(my_list)
for element in new_iter:
    print(element)

② 迭代器与循环终止条件:在使用 while 循环结合 next() 函数手动迭代时,需要正确处理 StopIteration 异常来控制循环终止。

python 复制代码
my_list = [1, 2, 3]
my_iter = iter(my_list)
while True:
    try:
        element = next(my_iter)
        print(element)
    except StopIteration:
        break

深入理解迭代器的基础概念与原理,是掌握Python进阶编程的重要一步。从可迭代对象到迭代器的转换,再到各种内置工具的使用,以及实际应用中的问题处理,这些基础知识构成了灵活运用迭代器的基石。通过不断实践,能够更加熟练地使用迭代器优化代码,提升程序的性能与可读性。

我是玉笥寻珍,正在持续更新中,感谢您的关注

相关推荐
凤年徐6 分钟前
【数据结构初阶】顺序表的应用
c语言·开发语言·数据结构·c++·笔记·算法·顺序表
蹦蹦跳跳真可爱58912 分钟前
Python----目标检测(《SSD: Single Shot MultiBox Detector》论文和SSD的原理与网络结构)
人工智能·python·深度学习·神经网络·目标检测·计算机视觉
LeonDL16844 分钟前
HALCON 深度学习训练 3D 图像的几种方式优缺点
人工智能·python·深度学习·3d·halcon·halcon训练3d图像·深度学习训练3d图像
walkskyer1 小时前
使用 Golang `testing/quick` 包进行高效随机测试的实战指南
开发语言·后端·golang
南瓜胖胖1 小时前
【R语言编程绘图-mlbench】
开发语言·机器学习·r语言
Rousson1 小时前
硬件学习笔记--65 MCU的RAM及FLash简介
开发语言·前端·javascript
慧都小妮子2 小时前
跨平台浏览器集成库JxBrowser 支持 Chrome 扩展程序,高效赋能 Java 桌面应用
开发语言·python·api·jxbrowser·chrome 扩展程序
范纹杉想快点毕业2 小时前
C++多重继承详解与实战解析
开发语言·c++
shenyan~2 小时前
关于 smali:2. 从 Java 到 Smali 的映射
java·开发语言