今天系统学习了 Python 中迭代器、生成器以及文件操作的核心知识点,这些内容是 Python 进阶的重要基础,尤其是迭代器和生成器的惰性计算特性,在处理大数据场景时能显著优化性能,下面对所学内容进行详细梳理。

一、迭代器(Iterator)

1. 核心概念

        可迭代对象:能被for循环遍历的对象,本质是实现了__iter__方法。
        检查是否为可迭代对象:hasattr(对象, '__iter__'),返回True则是可迭代对象。
        常见可迭代对象:列表、字符串、元组、自定义类实例(手动实现__iter__)。


        迭代器:遵循「迭代器协议」的对象,需同时满足两个条件:
                能被iter()接收(实现__iter__方法,且返回自身);
                能被next()逐步取值(实现__next__方法)。

        迭代器特性:
                惰性计算:按需生成值,不一次性加载所有数据,降低内存占用;
                一次性:状态只能前进,遍历后会被消耗,无法重复使用;
                调用next()取值,无数据时抛出StopIteration异常。

2. for 循环的底层逻辑

# 以遍历列表为例
names = ['张三','李四','王五']
it = iter(names)  # 1. 获取可迭代对象的迭代器
while True:
    try:
        print(next(it))  # 2. 调用next()取值
    except StopIteration:  # 3. 捕获异常,终止循环
        break

3. 自定义迭代器

        自定义迭代器有两种实现方式,核心是实现__iter__和__next__方法:

        方式 1:类自身作为迭代器(迭代器 = 可迭代对象)

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.__index = 0
        self.__arr = [name, age]
    
    def __iter__(self):
        return self  # 返回自身作为迭代器
    
    def __next__(self):
        if self.__index < len(self.__arr):
            self.__index += 1
            return self.__arr[self.__index - 1]
        else:
            raise StopIteration  # 无数据时抛异常

p1 = Person('张三',18)
for i in p1:
    print(i)  # 遍历输出:张三 18

        方式 2:分离可迭代对象和迭代器(更符合规范)

class Person:  # 可迭代对象
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.hobby = []
    
    def __iter__(self):
        return PersonIterator(self)  # 返回独立的迭代器对象

class PersonIterator:  # 迭代器类
    def __init__(self, p):
        self.p = p
        self.index = 0
        self.arr = [p.name, p.age, p.hobby]
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.arr):
            raise StopIteration
        value = self.arr[self.index]
        self.index += 1
        return value

4. 迭代器的优势(惰性计算)

        以斐波那契数列为例,对比列表生成和迭代器生成的内存占用:

import tracemalloc

# 迭代器实现(惰性计算,内存占用极低)
class Fib:
    def __init__(self,total):
        self.one = 1
        self.two = 1
        self.total = total
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= self.total:
            raise StopIteration
        if self.index < 2:
            self.index += 1
            return self.one
        self.three = self.one + self.two
        self.one = self.two
        self.two = self.three
        self.index += 1
        return self.three

# 列表实现(一次性生成所有数据,内存占用高)
def fib(n):
    num = [1,1]
    for i in range(n):
        num.append(num[i]+num[i+1])
    return num[:n]

# 内存对比
tracemalloc.start()
f1 = Fib(80)
m1 = tracemalloc.get_traced_memory()[1]
print(f'迭代器内存占用:{m1/1024/1024}MB')  # 接近0MB

tracemalloc.start()
f2 = fib(80)
m1 = tracemalloc.get_traced_memory()[1]
print(f'列表内存占用:{m1/1024/1024}MB')  # 远大于迭代器

二、生成器(Generator)

        生成器是 Python 内置的「简化版迭代器」,无需手动实现__iter__和__next__,核心是yield关键字。

1. 生成器函数的定义

        函数体中出现yield关键字,该函数即为生成器函数;
        调用生成器函数时,不会立即执行函数体,而是返回一个生成器对象

def test():
    print('函数开始执行')
    yield 'one'  # 暂停并返回值
    a = 200
    print(a)
    yield 'two'

res = test()  # 生成器对象,函数未执行
print(type(res))  # <class 'generator'>

2. 生成器的执行逻辑

        调用next(生成器)或生成器.__next__(),函数开始执行,遇到yield暂停,记录暂停位置;
        再次调用next(),从暂停位置继续执行,直到再次遇到yield;
        遇到return时,抛出StopIteration异常,return后的内容作为异常信息返回;
        yield后的值,会作为本次next()的返回值。

res = test()
print(next(res))  # 执行到第一个yield,输出:函数开始执行 → 返回one
print(next(res))  # 从暂停位置继续,输出:200 → 返回two
# 第三次next()会抛StopIteration(无更多yield)

3. 生成器的常用操作

        (1)for 循环遍历生成器

                生成器是可迭代对象,可直接用for循环

def car():
    for i in range(3):
        yield f'第{i+1}次打印'

a = car()
for i in a:
    print(i)  # 输出:第1次打印 第2次打印 第3次打印

        (2)yield from:批量 yield 可迭代对象的元素

def demo():
    nums = [1, 2, 3]
    yield from nums  # 等价于:for num in nums: yield num

a = demo()
print(next(a))  # 1
print(next(a))  # 2

        (3)send ():双向通信(给 yield 传值)

        next()只能取值,send()可同时「传值 + 取值」,注意:
                第一次启动生成器,需用next()或send(None)
                a = yield '返回值':右侧值返回给外部,左侧接收外部send的参数。

def demo():
    print('函数开始执行')
    a = yield '我是第一次返回值'  # 接收send的参数
    print(a,'@@@')
    b = yield '我是第二次返回值'
    print(b,'$$$')
    return 'hello'

d = demo()
d1 = next(d)  # 启动生成器,返回:我是第一次返回值
d2 = d.send('55')  # 给上一个yield传值55,返回:我是第二次返回值
try:
    d3 = d.send(777)  # 传值777,触发return,抛StopIteration
except StopIteration as e:
    print(e)  # 输出:hello(return的内容)

三、文件操作

1. 文件分类

类型编码方式示例文件读取 / 写入要求
纯文本文件遵循字符编码(如 utf-8).txt、.py、.md需指定编码,读取为字符串
二进制文件无字符编码,按格式存储.mp3、.png、.doc以二进制模式(b)操作,无需编码

2. 文件路径

        绝对路径:从文件系统根目录开始,如D:\Apython\SPT2603\4.文件操作\1.文件分类.py;
        相对路径:以当前工作目录为参照,如a.txt(当前目录下)、../b.txt(上级目录)。

3. 文件操作流程

        核心步骤:创建文件对象 → 操作文件 → 关闭文件(推荐用with自动关闭)。

(1)读取文件

        文件打开模式:rt(文本读取,默认)、rb(二进制读取)。

方法作用
read(size)无参数:读取全部内容;有参数:读取指定字符数(文本)/ 字节数(二进制)
readline()读取一行,size参数仅限制当前行的读取长度
readlines()无参数:返回所有行的列表;有参数:读取包含指定字符数的所有行
for line in f逐行遍历文件(推荐,惰性读取,低内存)
# 逐行读取(最优方式)
with open('a.txt', mode='rt', encoding='utf-8') as f:
    for line in f:
        print(line, end='')  # end=''避免重复换行

(2)写入文件

文件打开模式:
        wt:清空后写入,文件不存在则创建;
        xt:排他性创建,文件存在则报错;
        at:追加写入,文件不存在则创建;
        rt+/wt+:读写模式(需注意指针位置)。

# 追加写入
with open('a.txt', mode='at', encoding='utf-8') as f:
    f.write('追加的内容')

# 强制刷盘(跳过缓冲区,立即写入文件)
f.write('内容')
f.flush()

(3)文件指针(seek ())

调整文件读写指针位置,格式:f.seek(offset, whence)
        offset:偏移量(字节数);
        whence:参考点(0 = 文件开头,1 = 当前位置,2 = 文件末尾);
        文本模式(t):whence=1/2时,offset只能为 0;二进制模式(b)无限制。

with open('a.txt', mode='rt+', encoding='utf-8') as f:
    f.seek(0, 2)  # 指针移到文件末尾
    f.write('在末尾追加内容')

四、核心总结

        迭代器:手动实现__iter__+__next__,惰性计算,适合大数据场景,是可迭代对象的「取值工具」;
        生成器:内置迭代器,通过yield简化迭代器实现,支持send()双向通信,代码更简洁;
        文件操作:区分文本 / 二进制文件,优先用with自动关闭文件,读取大文件推荐逐行遍历,写入注意模式选择和缓冲区刷盘;
        迭代器和生成器的核心价值:惰性计算,降低内存占用,处理无限序列 / 超大文件时优势显著。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐