Python3 迭代器与生成器
1.迭代器
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器
迭代器的定义
- 字面意思:更新迭代,器:工具:可更新迭代的工具。
- 专业角度:内部含有
'__iter__'
方法并且含有'__next__'
方法的对象就是迭代器。 - 可以判断是否是迭代器:
'__iter__'
and'__next__'
在不在dir(对象)
当我们遇到可迭代对象但想将它当作迭代器使用时可以使用iter()方法转化。
li_=iter(li)
print(type(li_))
#输出为“list_iterator",即已经转换为迭代器。
可迭代对象
- 字面意思:可以进行循环更新的一个实实在在值。
- 专业角度: 内部含有
'__iter__'
方法的对象,可迭代对象。 - 判断一个对象是不是可迭代对象:
'__iter__'
in dir(对象)
迭代器和可迭代对象的区别
- 如果定义类时,有__iter__方法,那么这个类创建出来的对象一定是可迭代对象。
- 迭代器有两个基本的方法:iter() 和 next(),一个实现了__iter__方法和__next__方法的对象,就是迭代器。
- 迭代器对象 一定是 可迭代对象;可迭代对象 不一定是 迭代器;因此迭代器中包括可迭代对象没有的属性和方法,比如__next__()。
字符串,列表或元组对象(可迭代对象)都可用于创建迭代器(转换为迭代器):
list=[1,2,3,4]
it = iter(list) # iter()获取一个可迭代对象的迭代器
print (next(it)) # next()获取迭代器的数据
print (next(it))
# 输出 1 2
# 迭代器对象可以使用常规for语句进行遍历:
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
for x in it:
print (x, end=" ")
# 输出 1 2 3 4
创建一个迭代器(自定义迭代器)
把一个类作为一个迭代器使用需要在类中实现两个方法 iter() 与 next() 。iter() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。next() 方法会返回下一个迭代器对象。
创建一个返回数字的迭代器,初始值为 1,逐步递增 1,StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 5:
x = self.a
self.a += 1
return x
else:
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)
执行输出结果为:
1
2
3
4
5
2.生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,并返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。
以下实例使用 yield 实现斐波那契数列:
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()0 1 1 2 3 5 8 13 21 34 55
执行以上程序,输出结果如下:
0 1 1 2 3 5 8 13 21 34 55
yield a
:yield
是 Python 中一个非常有用的关键字,它用于定义生成器函数并返回生成器对象。当生成器函数执行到yield
关键字时,它将将当前函数状态保存为暂停状态,并向调用方返回一个值a
,之后程序流程将被挂起,直到下次通过next()
函数调用该生成器对象时再恢复执行状态。在斐波那契数列生成器函数中,每次执行到yield a
时,都会生成当前数列的第一个数字a
并返回给调用方。a, b = b, a + b
: 这是 Python 中的一种元组赋值语法,可以同时将多个变量赋值为多个值。在斐波那契数列生成器函数中,这行代码的作用是更新相邻两个数字a
和b
的值,以便生成下一个斐波那契数。首先,变量a
被赋值为变量b
的值,表示将上一个斐波那契数列中的第二个数字赋值为下一个数列的第一个数字;然后,变量b
被赋值为表达式a + b
的值,表示将上一个斐波那契数列中的前两个数字相加得到下一个数列中的第二个数字。这样,在每次执行yield a
之前,都会先更新a
和b
的值,从而生成下一个斐波那契数。
示例一
一个函数 f,f 返回一个 list,这个 list 是动态计算出来的(不管是数学上的计算还是逻辑上的读取格式化),并且这个 list 会很大(无论是固定很大还是随着输入参数的增大而增大),这个时候,我们希望每次调用这个函数并使用迭代器进行循环的时候一个一个的得到每个 list 元素而不是直接得到一个完整的 list 来节省内存,这个时候 yield 就很有用。
以斐波那契函数为例,我们一般希望从 n 返回一个 n 个数的 list:
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
上面那个 fab 函数从参数 max 返回一个有 max 个元素的 list,当这个 max 很大的时候,会非常的占用内存。
一般我们使用的时候都是这个样子的,比如:
f = iter(fab(1000))
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
这样我们实际上是先生成了一个 1000 个元素的 list:f,然后我们再去使用这个 f。
现在,我们换一个方法:
因为我们实际使用的是 list 的遍历,也就是 list 的迭代器。那么我们可以让这个函数 fab 每次只返回一个迭代器——一个计算结果,而不是一个完整的 list:
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print b
a, b = b, a + b
n = n + 1
这样,我们每次调用fab函数,比如这样:
for x in fab(1000):
print(x)
或者 next 函数之类的,实际上的运行方式是每次的调用都在 yield 处中断并返回一个结果,然后再次调用的时候再恢复中断继续运行。
3.迭代器与生成器区别
迭代器和生成器算是 Python 一大特色,其核心是基于迭代器协议来的。
而平时我们经常使用的 for in 循环体,本质就是迭代器协议的一大应用。
同时 Python 内置的集合类型(字符、列表、元组、字典)都已经实现了迭代器协议,所以才能使用 for in 语句进行迭代遍历。for in 循环体在遇到 StopIteration 异常时,便终止迭代和遍历。
再说下可迭代、迭代器、生成器三个概念的联系和区别。
1、可迭代概念范围最大,生成器和迭代器肯定都可迭代,但可迭代不一定都是迭代器和生成器,比如上面说到的内置集合类数据类型。可以认为,在 Python 中,只要有集合特性的,都可迭代。
2、迭代器,迭代器特点是,均可以使用 for in 和 next 逐一遍历。
3、生成器,生成器一定是迭代器,也一定可迭代。
4.for…in… 循环的本质
1.先调用 iter()函数,它会自动调用可迭代对象中的 __iter__方法,此方法返回这个可迭代对象的 迭代器对象
2.对获取到的迭代器不断调用 next()函数,它会自动调用迭代器中的 __next__方法来获取下一个值
3.当遇到 StopIteration异常后循环结束
4.for 循环可以迭代任何可迭代对象。
标签:__,迭代,对象,生成器,iter,next,Python3 From: https://www.cnblogs.com/littlecamel/p/18053860