Python可迭代(Iterable)、迭代器(Iterator)和生成器(Generator)
admin
2024-03-28 03:08:47

可迭代对象 Iterable

可迭代对象(Iterable):一个对象只要实现了__iter__()方法,那么用isinstance()函数检查就Iterable对象。

例如:

class IteraObj:def __iter__(self):# 这里简单地返回自身# 但实际情况可能不会这么写# 而是通过内置的可迭代对象来实现# 下文的列子中将会展示return selfit = IterObj()
print(isinstance(it, Iterable))  # true
print(isinstance(it, Iterator))  # false
print(isinstance(it, Generator)) # false

常见的可迭代对象:

  1. 集合或序列类型,如list, tuple, set, dict, str
  2. 文件对象;
  3. 在类中定义 __iter__() 方法的对象;

自定义的Iterable对象,要满足在 for 循环中正确使用,必须保证 __iter__() 方法正确实现(可以通过内置 iter()函数将其转换成Iterator对象)。

  1. 在类中只定义 __getiem__() 方法的对象,可以通过 iter() 函数转化成 Iterator 对象。即 一个对象能够在 for 循环中运行, 但不一定是Iterable对象。

首先验证1,2

具体如下:

# 1. 
from collections import Iterable, Iterator
print(isinstance([], Iterable)) # true   list是可迭代的  
print(isinstance({}, Iterable)) # true   dict是可迭代的
print(isinstance((), Iterable)) # true   tuple是可迭代的
print(isinstance(set(),  Iterable)) # true  set是可迭代的
print(isinstance('', Iterable)) # true  str是可迭代的print(isinstance([], Iterator))  # False  
print(isinstance({}, Iterator))  # False  
print(isinstance((), Iterator)) # False  
print(isinstance(set(),  Iterator))  # False  
print(isinstance('', Iterator)) # False  # 2.
cur_path = os.path.dirname(os.path.abspath(__file__))
with open(cur_path + '/model.py') as f:print(isinstance(f, Iterable))  # trueprint(isinstance(f, Iterator))  # true# 3.
print(hasattr([], '__iter__'))  # true
print(hasattr({}, '__iter__'))  # true
print(hasattr((), '__iter__'))  # true
print(hasattr('', '__iter__'))  # true

结论:集合和序列对象是可迭代的但不是迭代器。

这些内置集合或序列对象都含有 __iter__属性,是Iterable对象。但它们要在 for 循环中被使用,就应该能够被内置的 iter() 函数调用并转化成 Iterator 对象。

例如:

print(iter([])) # 
print(iter({})) # 
print(iter(())) # 
print(iter('')) # 

这些内置集合或序列为Iterable对象, 都可以转换为对应的 Iterator对象。

其次验证3

再回头修改自定的 IterObj

class IterObj:def __init__(self):self.a = [3, 5, 7, 11, 13, 17, 19]def __iter__(self):return iter(self.a)it = IterObj()
print(isinstance(it, Iterable)) # true
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) # false
print(iter(it)) # 
for i in it:print(i) # 将打印3、5、7、11、13、17、19元素

结论:在定义一个Iterable对象是,要注意__iter__() 方法的内部实现逻辑, 一般情况下,利用一些已知的 Iterable对象(如集合、序列、文件等或其他正确定义的Iterable对象)来辅助我们实现。

最后验证4
iter()函数可以将一个实现了 __getitem__() 方法的对象转换成Iterator对象,但他不是 Iterable对象。

例子:

class IterObj:def __init__(self):self.a = [3, 5, 7, 11, 13, 17, 19]def __getitem__(self, i):return self.a[i]it = IterObj()
print(isinstance(it, Iterable)) # false
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) false
print(hasattr(it, "__iter__")) # false
print(iter(it)) # for i in it:print(i) # 将打印出3、5、7、11、13、17、19

结论:可以在 for 中使用的对象,不一定是可迭代对象。

综上所述

  1. 一个 Iterable 对象是实现了 __iter__() 方法的对象;
  2. 它要在 for 中循环使用,就必须满足 iter() 的调用(即调用这个函数不会出错,能正确转成一个 Iterator 对象)
  3. 可以通过已知的 Iterable 对象来辅助实现我们自定义的Iterable 对象。
  4. 一个对象实现了 __getiem__() 方法, 可以通过 iter() 函数转换成 Iterator 对象,即可以在 for 循环中使用,但它不是一个Iterable 对象。

迭代器 Iterator

定义: 一个对象实现__iter__()__next__()两个方法,那么它就是一个Iterator对象。
作用: 遍历集合元素。注意:只能从开头顺序访问至结尾。
特点:

  1. 迭代器:一个可以记住遍历位置的对象。→ 节省内容
  2. 迭代器:有两个基本方法:iter()next()
  3. 可迭代对象:可通过iter()方法构建迭代器。
form collections import Iterable, Iteratorl = [1,2,3,4,5] 
print(isinstance(l, Iterable))  # True 可迭代对象
print(isinstance(l, Iterator))  # False 不是迭代器 it = iter(l)   # 创建迭代器对象
print(isinstance(it, Iterable))  # True 可迭代对象
print(isinstance(it, Iterator))  # False 不是迭代器 #  1. next() 顺序遍历迭代器
print(next(it), end=" ")  #2. for() 循环遍历迭代器
for x in it:   print(x)
  1. 自定义迭代器
  • __iter__() 方法 → 起始位置
  • __next__() 方法 → 下一个,终止位置
from collections import Iterable, Iterator
# 构建一个可以反向输出的列表可迭代对象
class listDemo(object):def __init__(self):self.__data = []self.__num = 0def __iter__(self):return selfdef __next__(self):if self.__num <= 0:raise StopIteration  # 终止else:self.__num -= 1return self.__data[self.__num]def __setitem__(self, key, value):  # 插入self.__data.insert(key, value)self.__num += 1def __getitem__(self, index):  # 读取return self.__data[index]def __delitem__(self, index):  # 删除del self.__data[index]self.__num -= 1def __len__(self):return len(self.__data)mylist = listDemo()
mylist[0], mylist[1], mylist[2], mylist[3] = '1', '2', '3', '4'
print('Iterable:', isinstance(mylist, Iterable))
print('Iterator:', isinstance(mylist, Iterator))# 法1: 无需iter(), 因为该对象已为迭代器对象
print(next(mylist))
print(next(mylist))# 法2: 从当前迭代器位置 for循环
for i in mylist:print(i, end=" ")del mylist[2]
print(len(mylist))
print(type(mylist))

斐波那契迭代器
相关知识

class Fibonacci():  # 定义迭代器类def __init__(self):self.a = 0self.b = 1def __iter__(self):return selfdef __next__(self):if self.b > 100:raise StopIteration      # 结束条件else:self.a, self.b = self.b, self.a + self.breturn self.afib = Fibonacci()  # 实例化迭代器对象# for 循环
for f in fib:print(f, end=' ')

生成器

方式:

  1. 列表生成器 → 节省内存
  2. 使用·yield·定义生成器

特点:
一个生成器对象既是可迭代对象,也是迭代器对象。

验证方式1

from collections import Iterator, Iterable, Generator
g = (x * 2 for x in range(10))  # 0~18的偶数生成器
print(isinstance(g, Iterable))  # true
print(isinstance(g, Iterator))  # true
print(isinstance(g, Generator))  # true
print(hasattr(g, "__iter__"))  # true
print(hasattr(g, "__next__"))  # trueprint(next(g))  # 0
print(next(g))  # 2for x in g:print(x, end=' ')

验证方式2

  1. yield的作用相当于return,可通过next()函数或for循环遍历。
  2. 程序执行遇到yield关键字,生成函数返回当前值,继续向下执行。
def gen():for i in range(5):print('before')yield i  # 生成器函数print('after')print('end')it = gen()
print(list(it)) # 直接将生成器能生成的所有值存储成列表或者元组的形式it2 = gen()
print(next(it2))
print(it2.__next__())it3 = gen()
for i in it3:print(i, end=" ")

参考资料

一文彻底搞懂Python可迭代(Iterable)、迭代器(Iterator)和生成器(Generator)的概念

相关内容

热门资讯

国庆黄金周景区情况:大同古城半... 文| 芙昕 编辑 | 芙昕 国庆长假,很多人都计划着出门走走,可一到了那些热门景点,看到的往往不是山...
来大东北一共分两步:先“冷藏”... 还在被“东北=冰窖”的刻板印象吓退? 南方的“小土豆”们 别急着裹紧小棉袄 这个冬天 让“气候缓冲带...
第三届“长城之约”活动在河北涞... 11月15日,第三届"长城之约"全球推广活动暨世界文化遗产对话15日在河北省保定市涞源县启幕。 本次...
巴厘岛:时光在此停驻 (自由行... 曾几何时,世人只知巴厘岛而不知印尼。巴厘岛的美太过耀眼,以至于人们常常忘记——它只是印尼万千岛屿中最...