python:可迭代对象,迭代器,生成器函数,生成器的解析举例代码说明
Posted 呆呆象呆呆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python:可迭代对象,迭代器,生成器函数,生成器的解析举例代码说明相关的知识,希望对你有一定的参考价值。
0 总述
主要介绍可迭代对象(iterable)、迭代器(iterator)、生成器(generator)。
迭代
是python
最强大的功能之一,是访问集合元素的一种方法。
迭代的概念
迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。
1 可迭代对象(iterable)
1.1 定义介绍
- 在
python
中, 某对象实现__iter__()
方法或者实现__getitem__()
方法而且其参数从0开始索引,那么该对象就是可迭代对象
。定义可迭代对象时必须实现__iter__()
方法或者__getitem__()
方法。 - 使用
iter()
方法将可迭代对象
变成迭代器
。 - 通俗的说就是可以用
for
循环的对象都是可迭代对象。例如:list、dict、tuple、set、string。其实都是序列,所以说任何序列都是可迭代的对象, 其原因在于他们至少都会实现__getittem__()
方法。(序列都可以通过索引获取元素) - 是一种通俗的叫法,并不是指某种具体的数据类型。
- 迭代器有一种具体的迭代器类型,比如
list_iterator
,set_iterator
。可迭代对象实现了__iter__
方法,该方法返回一个迭代器对象。
1.2 对可迭代对象进行迭代操作的具体过程
- 调用可迭代对象的
__iter__()
方法,返回一个迭代器对象 - 调用迭代器的
__next__()
方法返回每一次迭代的内容,直到迭代完成后,抛出stopiteration异常
。 可迭代对象
之所以能迭代,是因为实现了__iter__()
方法。当使用for
循环时候,解释器会检查对象是否有__iter__ ()
方法,有的话就是调用它来获取一个迭代器。所以没有__iter__ ()
方法但实现了__getitem__ ()
,解释器会创建一个迭代器
,尝试从0开始按顺序遍历元素。如果尝试失败,Python
便会抛出TypeError
错误。
所以说虽然字符串、列表、元组、字典、集合等均不是迭代器,但是他们可以在for
中进行循环的原因是他们是可迭代对象
,在进行迭代操作中会有__iter__()
返回对应的迭代器
,本质上就是对调用__iter__()
后得到的迭代器
通过不断使用next()
函数实现的,例如:下面举例说明:
list_data = [1,2,3]
list_iterator = iter(list_data)
str_data = "1,2,3"
str_iterator = iter(str_data)
tuple_data = (1,2,3)
tuple_iterator = iter(tuple_data)
dict_data = "1":1,"2":2,"3":3
dict_iterator = iter(dict_data)
print(type(list_iterator))
print(type(str_iterator))
print(type(tuple_iterator))
print(type(dict_iterator))
使用while
循环模拟for...in
的作用
list1 = [1, 2, 3, 4, 5]
iterator = iter(list1) # 使用iter()转换为迭代器
iterator = list1.__iter__() # 使用__iter__()转换为迭代器
while True:
try:
print(iterator.__next__(), end = " ") # 使用__next__()函数进行迭代
# print(next(iterator)) # 使用next()函数进行迭代
except StopIteration as e:
break
1.3 创建一个可迭代对象
class Vector(object):
def __init__(self,components):
self.components = list(components)
def __iter__(self):
return iter(self.components)
V1 = Vector([1,2,3])
for i in V1:
print(i)
上面的例子中实现了 __iter__()
方法,解释器可以从类对象中重复地取出元素并打印。
1.4 判断是否是可迭代对象
如果要检查某一个对象是否为可迭代对象,其实可以使用isinstance()
函数,该函数用于判断对象是否为某一类型。
# Python 3.9之前
from collections import Iterable
print(isinstance([1,2,3],Iterable))
# Python 3.9以后
from collections.abc import Iterable
print(isinstance([1,2,3],Iterable))
# 使用typing 库
from typing import Iterable
print(isinstance([1,2,3], Iterable))
举例说明:
class Vector(object):
def __init__(self,components):
self.components = list(components)
def __iter__(self):
return iter(self.components)
vector_data = Vector([1,2,3])
vector_iterator = iter(vector_data)
list_data = [1,2,3]
list_iterator = iter(list_data)
from typing import Iterable
from typing import Iterator
print("使用typing库Iterable和Iterator")
print("vector_data :是否为可迭代对象,是否为迭代器".format(isinstance(vector_data, Iterable),isinstance(vector_data, Iterator)))
print("vector_iterator:是否为可迭代对象,是否为迭代器".format(isinstance(vector_iterator, Iterable),isinstance(vector_iterator, Iterator)))
print("list_data :是否为可迭代对象,是否为迭代器".format(isinstance(list_data, Iterable),isinstance(list_data, Iterator)))
print("list_iterator :是否为可迭代对象,是否为迭代器".format(isinstance(list_iterator, Iterable),isinstance(list_iterator, Iterator)))
from collections.abc import Iterable
from collections.abc import Iterator
print("使用collections.abc库Iterable和Iterator")
print("vector_data :是否为可迭代对象,是否为迭代器".format(isinstance(vector_data, Iterable),isinstance(vector_data, Iterator)))
print("vector_iterator:是否为可迭代对象,是否为迭代器".format(isinstance(vector_iterator, Iterable),isinstance(vector_iterator, Iterator)))
print("list_data :是否为可迭代对象,是否为迭代器".format(isinstance(list_data, Iterable),isinstance(list_data, Iterator)))
print("list_iterator :是否为可迭代对象,是否为迭代器".format(isinstance(list_iterator, Iterable),isinstance(list_iterator, Iterator)))
注意点
如果可迭代对象只是实现了__getitem__()
的话,abc.Iterable
是不考虑该方法的,这便导致了isinstance()
判断不准确。更准确的方法应该是尝试调用iter()
函数,如果该对象不可迭代,就会抛出TypeError
的错误。
from collections.abc import Iterable
class Vector(object):
def __init__(self,components):
self.components = list(components)
def __getitem__(self,index):
return self.components[index]
V1 = Vector([1,2,3])
print(isinstance(V1,Iterable))
V1 = iter(V1)
print(isinstance(V1,Iterable))
2 迭代器(iterator)
迭代器
可以记住遍历对象的位置。其内部有一个状态用于记录迭代所在的位置,以便下次迭代时候能取出正确的元素迭代器
有两个基本方法iter()
、next()
。使用iter()
方法将可迭代对象
变成迭代器
。使用next()
方法返回下一个值。定义迭代器
,必须实现__iter__()
和__next__()
方法。(Python 2
里是需要类内有next()
方法)- 从集合的第一个元素开始访问,直到所有的元素被访问完结束。
迭代器
只能往前不会后退。 字符串
,列表
或元组对象
都可用于创建迭代器
。迭代器
一定是可迭代对象,但是可迭代对象
不一定是迭代器
。例如:字符串、字典、元组、集合等。迭代器
就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。
2.1 创建一个迭代器
next()
方法调用到末尾的时候会跳出StopIteration
,for
循环等就是在此时终止循环的
list_data = [1,2,3]
interator_data = iter(list_data)
print(interator_data)
print(type(interator_data))
print(next(interator_data))
print(next(interator_data))
print(next(interator_data))
print(next(interator_data))
2.2 判断是否是迭代器
可以参考1.4
2.3 使用for
进行迭代器的使用
list_data = [1,2,3]
interator_data = iter(list_data)
print(interator_data)
for i in interator_data:
print(i,end=" ")
2.4 使用next()
进行迭代器的使用
import sys
interator_data = iter([1,2,3])
while True:
try:
print (next(interator_data), end=" ")
except StopIteration:
sys.exit()
2.5 可迭代对象与迭代器的区别
迭代器
一定是可迭代对象
,但是可迭代对象
不一定是迭代器
。例如:字符串
、字典
、元组
、集合
等。
迭代器
可以使用next()
方法,但是可迭代对象
不一定可以使用next()
方法。
一般可以使用iter()
方法将可迭代对象
变成迭代器
。
list_data = [1,2,3]
interator_data = iter(list_data)
print(interator_data)
print(type(interator_data))
print(next(interator_data))
print(type(list_data))
print(next(list_data))
2.5 创建一个迭代器
定义一个类作为一个迭代器使用需要在类中实现两个方法 __iter__()
与 __next__()
。
类中成员函数__iter__()
在外部对类的示例化变量调用iter()
方法的时候会被调用,主要功能是实现返回一个特殊的迭代器对象(一般就是自己),(一般也会再次或者在__init__()
中设置迭代器的七点)。
类内成员函数__next__()
在外部对类的示例化变量调用next()
方法的时候会被调用,会返回迭代器
中下一个需要被迭代出的值,一般中间应该有StopIteration
异常,对迭代
的完成进行标识控制。
创建一个返回数字的迭代器,初始值为 1,逐步递增 1:
class My_interator:
def __iter__(self):
self.start_number = 1
return self
def __next__(self):
if self.start_number <= 10:
x = self.start_number
self.start_number += 1
return x
else:
raise StopIteration
interator_class = My_interator() # 实例化对象
interator_data = iter(interator_class) # 对实例化对象使用iter() 返回迭代器
for x in interator_data:# 对迭代器进行迭代
print(x,end = " ")
3 生成器(generator)
3.1 定义介绍
- 在
Python
中,使用了yield
的函数被称为生成器函数generator function
。调用一个生成器函数
,返回的是一个实例化迭代器对象
。 - 跟普通函数不同的是,
生成器函数
是一个返回生成器
的函数,只能用于迭代操作,更简单点理解生成器
就是一种特殊的迭代器
。生成器
自动实现了“迭代器协议”(即__iter__()
和__next__()
方法),不需要再手动实现两方法。 生成器
在迭代的过程中可以改变当前迭代值,而修改普通迭代器
的当前迭代值往往会发生异常,影响程序的执行。(因为生成器
有send()
方法)- 在调用
生成器
运行的过程中,每次遇到yield
时函数会暂停并保存当前所有的运行信息,返回yield
语句表达式的值, 并在下一次执行next()
或send()
方法时从当前位置继续运行。 - 列表对内存的开销比较大。如果列表元素可以按照某种算法推算出后面的元素,这样就不必创建完整的列表。在
python
中我们把一边循环一边计算的机制,即为生成器generator
。
3.2 创建生成器的例子
def myList(num): # 定义生成器
now = 0 # 当前迭代值,初始为0
while now < num:
val = (yield now) # 返回当前迭代值,并接受可能的send发送值;
now = now + 1 if val is None else val # val为None,迭代值自增1,否则重新设定当前迭代值为val
my_list = myList(5) # 得到一个生成器对象
print my_list.next() # 返回当前迭代值
print my_list.next()
my_list.send(3) # 重新设定当前的迭代值
print my_list.next()
3.3 判断是否是生成器函数或生成器
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 使用 yield
a, b = b, a + b
n = n + 1
from inspect import isgeneratorfunction
print(isgeneratorfunction(fab))
print(isgeneratorfunction(fab(5)))
import types
print(isinstance(fab, types.GeneratorType) )
print(isinstance(fab(5), types.GeneratorType))
3.5 关于更多举例说明
参考专门讲解生成器运行原理和yield
关键字的文章。
3.6 生成器表达式(generator expression)
生成器表达式
是列表推导式的生成器版本,看起来像列表推导式,但是它返回的是一个生成器对象
而不是列表对象
。
a = (x*x for x in range(10))
print(type(a))
print(next(a))
print(next(a))
print(sum(a)) # 注意因为运行了两次之后0,1已经不在生成器能访问的位置中了, sum求和出来为284而不是285
LAST 参考文献
python中可迭代对象、迭代器、生成器等都有什么区别 - 华为云
Python3.9中,使用from collections import Iterable报错_qq_39321623的博客-CSDN博客
python中可迭代对象、迭代器、生成器等都有什么区别 - 华为云
黄哥Python:如何判断一个对象是生成器还是迭代器? - 知乎
理解Python可迭代对象、迭代器、生成器 - stardsd - 博客园
跟你深入剖析可迭代对象和迭代器的区别与联系 - SegmentFault 思否
python中yield的用法_呆呆象呆呆的博客-CSDN博客
理解Python可迭代对象、迭代器、生成器 - stardsd - 博客园
Python可迭代对象,迭代器,生成器的区别_Nxin的小抄本-CSDN博客
(1 封私信 / 82 条消息) 如何更好地理解Python迭代器和生成器? - 知乎
以上是关于python:可迭代对象,迭代器,生成器函数,生成器的解析举例代码说明的主要内容,如果未能解决你的问题,请参考以下文章
python:可迭代对象,迭代器,生成器函数,生成器的解析举例代码说明