【python面向对象编程】迭代器与生成器
面向对象编程(OOP,Object-Oriented Programming)
迭代器(Iterators)
生成器(Generators)
迭代器
1.可迭代对象 vs. 迭代器
可迭代对象 (Iterable): 一个可以逐个返回其元素的对象。例如:list, str, tuple, dict, set, file 等。你肉眼可以看到它的所有或部分内容。
迭代器 (Iterator): 一个表示数据流的对象。它被调用一次,就返回流中的下一个数据。它就像一个“懒加载”的工厂,你向它要一个,它才生产一个。你无法直接看到流里还有多少数据。
2.iter()
函数
功能:
iter()
函数的作用就是将一个可迭代对象转换成一个迭代器。
语法:
iter(iterable)
参数:任何可迭代的对象。
返回值:返回一个迭代器对象。
3.使用迭代器:next()
函数
功能:使用 next() 函数来逐个获取其中的值。
语法:
1.每次调用next(iterator)
,都会返回迭代器中的下一个元素。
2.当所有元素都被取出后,再次调用 next() 会引发一个StopIteration
异常,告诉你数据已经取完了。
4.示例
示例 1:从列表创建迭代器
# 创建一个可迭代对象:列表
my_list = [‘苹果’, ‘香蕉’, ‘橙子’]# 使用 iter() 将其转换为迭代器
my_iterator = iter(my_list)# 使用 next() 逐个获取元素
print(next(my_iterator)) # 输出:苹果
print(next(my_iterator)) # 输出:香蕉
print(next(my_iterator)) # 输出:橙子# 再次调用 next(),已经没有元素了,会抛出 StopIteration 异常
print(next(my_iterator)) # 引发 StopIteration
这个过程揭示了 for 循环的本质:
-你的 for 循环:
for item in my_list:print(item)
-Python 背后:
调用 iter(my_list)
得到一个迭代器。
反复调用 next(iterator)
来获取下一个值,并赋值给 item。
当遇到 StopIteration
异常时,自动结束循环。
示例 2:文件对象本身就是迭代器
处理文件时,我们经常逐行读取,这其实就是迭代器的完美应用。
# 打开一个文件,file 本身就是一个迭代器
with open('myfile.txt') as f:# 直接使用 next() 读取第一行first_line = next(f)print(first_line)# for 循环会自动接着从第二行开始读取for line in f:print(line, end='') # 打印余下的所有行
5.iter()
的高级用法:双参数形式
语法:
iter(callable, sentinel)
不常用但很有用
参数与功能:
callable
: 一个可调用对象(比如函数)。
sentinel
: 一个“哨兵值”。当可调用对象返回这个值时,迭代停止。
示例:创建一个不断读取输入直到满足条件的迭代器
import random# 定义一个总是返回随机数的函数
def get_random():return random.randint(1, 10)# 创建一个迭代器,当 get_random() 返回 5 时停止
random_iterator = iter(get_random, 5)# 这个 for 循环会不停地打印随机数,直到某次随机数是 5
for num in random_iterator:print(num)
可能输出:
3
8
2
9
1
# 循环结束,因为下一次 get_random() 返回了 5
6. 判断迭代器
你可以使用 collections.abc
模块中的 Iterator
和 Iterable
来进行类型检查。
语法:
isinstance(my_list, Iterable)
:判断是否可迭代
isinstance(my_list, Iterator)
:判断是否为迭代器
from collections.abc import Iterator, Iterablemy_list = [1, 2, 3]
my_iterator = iter(my_list)print(isinstance(my_list, Iterable)) # True,列表是可迭代的
print(isinstance(my_list, Iterator)) # False,但列表本身不是迭代器print(isinstance(my_iterator, Iterable)) # True,迭代器也是可迭代的
print(isinstance(my_iterator, Iterator)) # True,它是正宗的迭代器
By now you have probably noticed that most container objects can be looped over using a for statement:
你现在可能注意到大多数容器对象都可以使用
for
语句循环
You can call the next() method using the next() built-in function; this example shows how it all works:for
你可以调用
__next__()
方法通过使用内置函数next();此示例显示了这一切的工作原理:for
>>>s = 'abc'
>>>it = iter(s)
>>>it
<str_iterator object at 0x10c90e650>
>>>next(it)
'a'
>>>next(it)
'b'
>>>next(it)
'c'
>>>next(it)
Traceback (most recent call last):File "<stdin>", line 1, in <module>next(it)
StopIteration
Having seen the mechanics behind the iterator protocol, it is easy to add iterator behavior to your classes. Define an iter() method which returns an object with a next() method. If the class defines , then can just return :next()iter()self
在了解了迭代器协议背后的机制之后,你可以很容易地为你的类添加迭代器行为。定义一个
__iter__()
方法,它返回一个带有__next__()
方法的对象。如果类有定义,则可以只返回:__next__()__iter__()self
class Reverse:"""Iterator for looping over a sequence backwards."""def __init__(self, data):self.data = dataself.index = len(data)def __iter__(self):return selfdef __next__(self):if self.index == 0:raise StopIterationself.index = self.index - 1return self.data[self.index]
>>>rev = Reverse('spam')
>>>iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>>for char in rev:
... print(char)
...
m
a
p
s
生成器
def reverse(data):for index in range(len(data)-1, -1, -1):yield data[index]
>>>for char in reverse('golf'):
... print(char)
...
f
l
o
g
Anything that can be done with generators can also be done with class-based iterators
任何可以用生成器完成的事情,也可以用基于类的迭代器完成
生成器表达式
Some simple generators can be coded succinctly as expressions using a syntax similar to list comprehensions but with parentheses instead of square brackets. These expressions are designed for situations where the generator is used right away by an enclosing function. Generator expressions are more compact but less versatile than full generator definitions and tend to be more memory friendly than equivalent list comprehensions.
一些简单的生成器,可以简洁地编码为,那些语法类似于列表推导式的表达式,但用圆括号而不是方括号。 这些表达式专为,生成器被外层函数立即使用的情况而设计。生成器表达式比完整的生成器定义更简洁但功能较少,通常比等效的列表推导式更节省内存。
>>>sum(i*i for i in range(10)) # sum of squares
285>>>xvec = [10, 20, 30]
>>>yvec = [7, 5, 3]
>>>sum(x*y for x,y in zip(xvec, yvec)) # dot product
260>>>unique_words = set(word for line in page for word in line.split())>>>valedictorian = max((student.gpa, student.name) for student in graduates)>>>data = 'golf'
>>>list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']
References:https://docs.python.org/3/tutorial/classes.html