迭代器?
你有没有想过在python里for i in lit遍历一个列表,他究竟干了什么,为什么有的变量可以循环,而有的不可以for遍历?就比如说for i in 2,对一个数字遍历会报错
TypeError: 'int' object is not iterable,这句话意思是int对象不是迭代器,看来想要迭代,还必须要有一定的属性,而这个属性就是__iter__以及__next__成员方法。
现在我用一个学生对象来举例迭代器,假设我想用for循环打印该学生的所有属性值:
- 第一步:对学生类创建__iter__成员方法
该方法用于返回迭代器,你可以直接返回一个可迭代对象比如list或元组等内置对象,也可以返回self自己本身,只不过返回self本身,你就需要写__next__函数的逻辑。 - 第二步:添加__next__方法
如果返回self本身作为迭代器就需要__next__方法,这个方法用于填写返回值的逻辑以及什么时候遍历终止。在迭代完毕时,需要抛出StopIteration来告知没有元素可以迭代!
python
class Student:
def __init__(self, name, age, stu_id, grade):
# 初始化学生属性
self.name = name # 姓名
self.age = age # 年龄
self.stu_id = stu_id # 学号
self.grade = grade # 成绩
def __iter__(self):
# 迭代器初始化方法:返回迭代器对象本身
# 定义一个索引,用来遍历属性列表
self.index = 0
# 把对象的所有属性存入列表(固定遍历顺序)
self.attributes = [self.name, self.age, self.stu_id, self.grade]
return self
def __next__(self):
# 迭代器核心:每次调用返回下一个属性
if self.index < len(self.attributes):
# 获取当前属性
value = self.attributes[self.index]
# 索引+1,为下一次迭代做准备
self.index += 1
return value
# 迭代完毕,抛出停止迭代异常
raise StopIteration
# 测试代码
if __name__ == '__main__':
# 创建学生对象
stu = Student("张三", 18, "2025001", 95)
# 迭代遍历学生所有属性(for循环自动调用迭代器)
print("学生所有属性:")
for attr in stu:
print(attr)
# 手动调用迭代器(验证手写迭代器生效)
print("\n手动迭代属性:")
iter_obj = iter(stu)
print(next(iter_obj))
print(next(iter_obj))
print(next(iter_obj))
print(next(iter_obj))
所以定义迭代器有什么用,只是遍历?
迭代器在读取文件时大有用途,比如读取一个大型文件,你的目的是一行一行读取,在需要时读取下一行,于是你认为读取到列表里是不错的选择,但是发现一下子加载到内存就会有很大开销,于是迭代器登场了:
python
class LineReader:
def __init__(self, file_path):
# 打开文件
self.file = open(file_path, 'r', encoding='utf-8')
# 标记是否已经读取完毕
self.is_finished = False
def __iter__(self):
# 迭代器返回自身
return self
def __next__(self):
# 如果已经读完,直接抛出停止迭代
if self.is_finished:
self.file.close() # 关闭文件
raise StopIteration
# 读取一行
line = self.file.readline()
# 如果读到空字符串,说明文件结束
if not line:
self.is_finished = True
self.file.close()
raise StopIteration
# 去掉换行符并返回
return line.strip()
# ===================== 测试 =====================
if __name__ == '__main__':
# 先创建一个测试文件 test.txt
with open('test.txt', 'w', encoding='utf-8') as f:
f.write("第一行:我是学生\n")
f.write("第二行:学习Python\n")
f.write("第三行:手写迭代器\n")
f.write("第四行:逐行读取文件\n")
# 使用我们的逐行读取迭代器
print("=== 逐行读取内容 ===")
reader = LineReader("test.txt")
# for 循环自动迭代
for line in reader:
print(line)
这个迭代器可以实现一行一行读取文件,而且内存开销也不大,读完时也会自动关闭文件。
生成器函数
如果上面读取文件的代码太复杂,生成器也是不错选择。
生成器函数里必须有yield,每次遍历生成器,yield都会返回一个生成的内容,并且函数阻塞到这里,等到下次调用该生成器,会从这里继续执行后面的代码。
生成器生成1-9的例子
python
def test():
a=1
while a<10:
yield a
a+=1
for i in test():
print(i)
他的逻辑是这样的:for循环先从生成器拿到第一个值1,此时生成器阻塞在a+=1处,当for循环打印1后,再次从生成器取值,生成器从阻塞的地方继续执行,a+=1后yield返回2以此类推.注意下面是错误的写法:
python
def test():
a=1
if a<10:
yield a
a+=1
for i in test():
print(i)
生成器遍历文件
python
def read_file(file_path):
f = open(file_path, 'r', encoding='utf-8')
while True:
line = f.readline()
if not line:
break
yield line
f.close()
# 遍历
for line in read_file("test.txt"):
print(line)