迭代器

xiaoxiao2025-11-07  3

一、迭代器

定义:

对于list、string、tuple、dict等这些容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数。iter()是python内置函数。 iter()函数会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内的元素。next()也是python内置函数。在没有后续元素时,next()会抛出一个StopIteration异常,通知for语句循环结束。

迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的_next_方法Python3中是对象的_next_方法,Python2中是对象的next()方法)。所以,我们要想构造一个迭代器,就要实现它的_next_方法。

但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现_iter_方法,而_iter_方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的_iter_方法返回自身self即可。

一些术语的解释:

1,迭代器协议:对象需要提供next()方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代

2,可迭代对象:实现了迭代器协议对象。list、tuple、dict都是Iterable(可迭代对象),但不是Iterator(迭代器对象)。但可以使用内建函数iter(),把这些都变成Iterable(可迭代器对象)。

3,for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束

Python自带容器对象案例:

# 随便定义一个list listArray=[1,2,3] # 使用iter()函数 iterName=iter(listArray) print(iterName) # 结果如下:是一个列表list的迭代器 # <list_iterator object at 0x0000017B0D984278> print(next(iterName)) print(next(iterName)) print(next(iterName)) print(next(iterName))#没有迭代到下一个元素,直接抛出异常 # 1 # 2 # 3 # Traceback (most recent call last): # File "Test07.py", line 32, in <module> # StopIteration!

Python中一个实现了_iter_方法和_next_方法的类对象,就是迭代器,如下案例是计算菲波那切数列的案例

class Fib(object): def __init__(self, max): super(Fib, self).__init__() self.max = max def __iter__(self): self.a = 0 self.b = 1 return self def __next__(self): fib = self.a if fib > self.max: raise StopIteration self.a, self.b = self.b, self.a + self.b return fib # 定义一个main函数,循环遍历每一个菲波那切数 def main(): # 100以内的数 fib = Fib(100) for i in fib: print(i) # 测试 if __name__ == '__main__': main()

解释说明:

在本类的实现中,定义了一个_iter_(self)方法,这个方法是在for循环遍历时被iter()调用,返回一个迭代器。因为在遍历的时候,是直接调用的python内置函数iter(),由iter()通过调用_iter_(self)获得对象的迭代器。有了迭代器,就可以逐个遍历元素了。而逐个遍历的时候,也是使用内置的next()函数通过调用对象的_next_(self)方法对迭代器对象进行遍历。所以要实现_iter_(self)和_next_(self)这两个方法。

而且因为实现了_next_(self)方法,所以在实现_iter_(self)的时候,直接返回self就可以。

总结一句话就是: 在循环遍历自定义容器对象时,会使用python内置函数iter()调用遍历对象的_iter_(self)获得一个迭代器,之后再循环对这个迭代器使用next()调用迭代器对象的_next_(self)。

注意点:_iter_(self)只会被调用一次,而_next_(self)会被调用 n 次,直到出现StopIteration异常。

class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a,b def __iter__(self): return self # 实例本身就是迭代对象,故返回自己 def __next__(self): self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration(); return self.a # 返回下一个值

IJCNLP的例子:

注意:这个例子中没有__next(self)__,而是使用了yield.

这样产生的是一个生成器。所以更像下面谈到的生成器的用法。

iter(a)其实产生的for line in self.num_list:                                   yield line       这部分代码,相当于一个函数了

class FlashcardSentences(object): def __init__(self, num_list): self.num_list = num_list def __iter__(self): for line in self.num_list: yield line a=FlashcardSentences([3,2,3,4,5]) '''注意:这是生成器对象''' print(iter(a)) #<generator object __iter__ at 0x000002A7AC4998E0> for i in a: print(i) // class FlashcardSentences(object): def __init__(self, filename): self.filename = filename def __iter__(self): for line in open(self.filename, "rb"): line = line.strip() line = line.decode("utf8").encode("ascii", "ignore") _, question, answer = line.split("\t") qwords = nltk.word_tokenize(question) awords = nltk.word_tokenize(answer) yield qwords + awords

 

二、生成器

作用:

迭代器是一个对象,而生成器是一个函数,迭代器和生成器是python中两个非常强大的特性,编写程序时你可以不使用生成器达到同样的效果,但是生成器让你的程序更加pythonic。

创建生成器只要在函数中加入yield语句即可。函数中每次使用yield产生一个值,函数就返回该值,然后停止执行,等待被激活,被激活后继续在原来的位置执行。

也就是:每到yield执行完就暂停。

下边的例子实现了同样的功能: 

注意事项:

生成器是只能遍历一次的。

生成器是一类特殊的迭代器。

例子:

#!/usr/bin/env python #coding=utf-8 def fib(): a,b = 0,1 while 1: a,b = b,a+b yield a for f in fib(): if f < 10000: print f else: break

注意下面的例子:

f=Fib(10)会产生一个生成器,这里不需要使用iter()函数。 

def Fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return '亲!没有数据了...' # 调用方法,生成出10个数来 f=Fib(10) # 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中 while True: try: x=next(f) print("f:",x) except StopIteration as e: print("生成器最后的返回值是:",e.value) break def createGenerator(): mylist = range(3) for i in mylist: yield i*i mygenerator = createGenerator() # 创建生成器 print(mygenerator) # mygenerator is an object! #<generator object createGenerator at 0x000002A7AC499B48> for i in mygenerator: print(i)

在CNN情感分析中的例子:

def batch_iter(data, batch_size, num_epochs): """ Generates a batch iterator for a dataset. """ data = np.array(data) data_size = len(data) num_batches_per_epoch = int(len(data)/batch_size) + 1 for epoch in range(num_epochs): # Shuffle the data at each epoch shuffle_indices = np.random.permutation(np.arange(data_size)) shuffled_data = data[shuffle_indices] for batch_num in range(num_batches_per_epoch): #batch_num表示第几批 start_index = batch_num * batch_size end_index = min((batch_num + 1) * batch_size, data_size) yield shuffled_data[start_index:end_index]

 

转载请注明原文地址: https://www.6miu.com/read-5039245.html

最新回复(0)