迭代器和生成器初识
1迭代器
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()---------iter()是创建迭代器。
关于迭代器的一些简单用法有:
l=[1,2,3,4]
a=iter(l)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
输出:1
2
3
4
l=[1,2,3,4]
a=iter(l)
for i in a:
print(i)
输出:1
2
3
4
冒出来的感觉
来源于:Python3 迭代器与生成器 | 菜鸟教程 (runoob.com)
2生成器
1解释
生成器是一种特殊的迭代器,它可以通过函数中的yield语句来实现。生成器函数在每次调用时返回一个值,并在下一次调用时从上一次离开的地方继续执行。以下是一个用代码详细解释生成器的
以下是一个用代码解释生成器和迭代器关系的例子:
```python
class MyIterator:
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start < self.end:
value = self.start
self.start += 1
return value
else:
raise StopIteration
# 创建迭代器对象
my_iter = MyIterator(1, 4)
# 通过迭代器遍历值
for value in my_iter:
print(value)
```
在上面的例子中,我们定义了一个迭代器类`MyIterator`,它实现了`__iter__()`方法和`__next__()`方法。`__iter__()`方法返回迭代器对象本身,而`__next__()`方法定义了迭代器的行为。
我们创建了一个迭代器对象`my_iter`,并通过for循环遍历迭代器中的值。每次迭代时,for循环会自动调用迭代器对象的`__next__()`方法来获取下一个值。在`__next__()`方法中,我们检查当前值是否小于结束值,如果是,则返回当前值并更新下一个值;如果不是,则引发StopIteration异常来表示迭代结束。
需要注意的是,生成器是一种特殊的迭代器,它通过yield语句来实现迭代器的功能。在上面的例子中,我们可以将迭代器类`MyIterator`改写为生成器函数,如下所示:
```python
def my_generator(start, end):
while start < end:
yield start #返回start值
start += 1
# 创建生成器对象
gen = my_generator(1, 4)
# 通过生成器遍历值
for value in gen:
print(value)
```
这样,我们可以得到相同的结果。生成器函数`my_generator()`使用yield语句返回一系列的值,而不需要显式地实现`__iter__()`方法和`__next__()`方法。for循环会自动处理StopIteration异常,并在生成器没有更多的值可返回时退出循环。
例子:
```python
def my_generator():
yield 1
yield 2
yield 3
# 创建生成器对象
gen = my_generator()
# 通过调用__next__()方法获取生成器中的值
print(gen.__next__()) # 输出: 1
print(gen.__next__()) # 输出: 2
print(gen.__next__()) # 输出: 3
# 生成器在没有更多值可返回时会引发StopIteration异常
# print(gen.__next__()) # 引发StopIteration异常
```
在上面的例子中,我们定义了一个生成器函数`my_generator()`,它使用yield语句来返回一系列的值。当我们调用`my_generator()`时,它不会立即执行函数体,而是返回一个生成器对象`gen`。
在这个例子中,调用`gen.__next__()`方法是为了手动获取生成器中的值。
生成器对象是可迭代的,它可以通过for循环来遍历生成器中的值。但是,在这个例子中,我们选择手动调用`__next__()`方法来逐个获取生成器中的值。
调用`gen.__next__()`方法会使生成器函数从上一次离开的地方继续执行,直到遇到下一个yield语句。每次调用`__next__()`方法时,生成器函数会返回一个值。
在这个例子中,生成器函数`my_generator()`定义了三个yield语句,分别返回值1、2和3。通过连续调用`gen.__next__()`方法,我们可以逐个获取生成器中的值,并将其打印出来。
当生成器没有更多的值可返回时,它会引发StopIteration异常。这是因为生成器函数中的yield语句已经全部执行完毕,没有更多的值可返回。
在这个例子中,我们注释掉了最后一个`gen.__next__()`方法的调用,因此没有引发StopIteration异常。如果取消注释并运行该代码,会引发StopIteration异常,因为生成器已经没有更多的值可返回。
通常情况下,我们不需要手动调用`__next__()`方法来获取生成器中的值。我们可以使用for循环来自动遍历生成器中的值,并在生成器没有更多的值可返回时退出循环。这是因为for循环会自动处理StopIteration异常。
例如,我们可以使用for循环来遍历生成器中的值,如下所示:
```python
for value in gen:
print(value)
```
这样,我们可以逐个获取生成器中的值,并将其打印出来。当生成器没有更多的值可返回时,for循环会自动退出循环,不会引发StopIteration异常。
因此,在大多数情况下,我们可以使用for循环来遍历生成器中的值,而不需要手动调用`__next__()`方法。只有在特殊情况下,我们才需要手动调用`__next__()`方法来逐个获取生成器中的值。
这样,我们可以依次打印出生成器中的值1、2、3。
2解释
通过使用yeild语句,可以创建并返回不止一个结果,可以返回整个结果序列的函数,这种函数被称为生成器。(生成器是一种函数)
yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。
然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。
调用一个生成器函数,返回的是一个迭代器对象。
用代码例子解释如下:
def foo():
print("starting...")
while True:
res = yield 4
print("res:",res)
g = foo() #上边的foo()函数里边有yield,所以只能作为一个生成器,所以就只运行到print()
print(next(g)) #生成器中的next()函数就是接着foo()上一步没弄完的,遇见yield,返回4并停止
print("*"*20)
print(g.send(7)) #如果这个代码是print(next(g))的话,那么res就赋值为None.
#但是此处如果用send的话,开始执行的时候,先接着上一次(返回4之后)执行,先把7赋值给了res,然后执行next的作用,遇见下一回的yield,return出结果后结束。
输出:
starting...
4
********************
res: 7
4
代码引自:https://blog.youkuaiyun.com/mieleizhi0522/article/details/82142856
代码二:
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 使用 yield
# print b
a, b = b, a + b
n = n + 1
for n in fab(5):
print n
输出1
1
2
3
5
简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。
也可以手动调用 fab(5) 的 next() 方法(因为 fab(5) 是一个 generator 对象,该对象具有 next() 方法),这样我们就可以更清楚地看到 fab 的执行流程
摘自:Python yield 使用浅析 | 菜鸟教程 (runoob.com:
3.一些运用的小例子
3.1关于for循环与生成器的运用
def foo(num):
print("starting...")
while num<10:
num=num+1
yield num
for n in foo(0):
print(n)
循环执行fab()内部代码,第一次循环,执行print,输出"starting...",0<10,num=1,返回num,print(n)。第二次循环继续上次yield结束那里,类似于continue,继续while循环,1<10,num=2,返回2,print(n)......
3.2关于怎样用迭代器执行求和的时间
def odd(n,m):
while n<m:
yield n #sum将每个数字都装入内存。通过生成器对象反复调用_next_()特殊方法来实现的,生成器只返回None之外的值。(所以,我以后会看懂的( ̄︶ ̄))
n+=2
sum(odd(1,100))
Thank you for reading!And welcome your advice.