成语| 古诗大全| 扒知识| 扒知识繁体

当前位置:首页 > 趣味生活

python为什么使用迭代器

Q1:python的迭代器为什么一定要实现

态关问题Python关于迭代两概念第Iterable第二Iterator协议规定Iterable
__iter__返Iterator, Iterator__next__(Python
2next)返迭代象迭代结束则抛StopIteration异
同Iterator自种Iterable所需要实现Iterable接口__iter__for两者都使用Iterator__iter__需要返自行面代码工作:
for i in my_list:
...
for i in iter(mylist):
...
for i in (v for v in mylist if v is not None):
...
Python许直接返iterator比itertools面izip等
Iterator自Iterable便需要先返Iterable象再让Iterable返Iterator器表
达式iterator显于器表达式直接使用for非重要
保留Iterator接口需要设计
Iterable呢许象比list、dict重复遍历甚至同并发进行遍历通__iter__每返独立迭代器
保证同迭代程互相影响器表达式类结往往性重复遍历所直接返Iterator让
Iterator实现Iterable兼容灵选择返哪种
总结说Iterator实现__iter__兼容Iterable接口让IteratorIterable种实现
补充题主于for理解基本确仍点点偏差:for兼容性其实两种机制象__iter__使用迭代器象没__iter__实现__getitem__改用标迭代式我试:
>>> class NotIterable(object):
... def __init__(self, baselist):
... self._baselist = baselist
... def __getitem__(self, index):
... return self._baselist[index]
...
>>> t = NotIterable([1,2,3])
>>> for i in t:
... print i
...
1、2、3、>>> iter(t)
for发现没__iter____getitem__候0始依读取相应标直发
IndexError止种旧迭代协议iter处理种情况存__iter__候返标迭代iterator
象代替重要例str字符串没__iter__接口

Q2:python迭代器的使用方法究竟是什么?

那你就在mylist类中实现__iter__和__next__方法(你这是Python3吧,Python2里应该是next方法)。
迭代器仅是一容器对象,它实现了迭代器协议。它有两个基本方法:
1)next方法
返回容器的下一个元素
2)__iter__方法
返回迭代器自身

Q3:python 迭代器和生成器的区别

Num01–>迭代器
定义:
对于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自带容器对象案例:
# 随便定义一个listlistArray=[1,2,3]# 使用iter()函数iterName=iter(listArray)
print(iterName)# 结果如下:是一个列表list的迭代器# 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 # StopIteration123456789101112131415161718、
Python中一个实现了_iter_方法和_next_方法的类对象,就是迭代器,如下案例是计算菲波那切数列的案例
class Fib(object):
def __init__(self, max):
super(Fib, self).__init__()
self.max = maxdef __iter__(self):
self.a = 0
self.b = 1、return selfdef __next__(self):
fib = self.aif fib > self.max:raise StopIteration
self.a, self.b = self.b, self.a + self.breturn fib# 定义一个main函数,循环遍历每一个菲波那切数def main():
# 20以内的数
fib = Fib(20)for i in fib:
print(i)# 测试if __name__ == __main__:
main()12345678910111213141516171819202122232425262728、
解释说明:
在本类的实现中,定义了一个_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异常。
Num02–>生成器
作用:
>延迟操作。也就是在需要的时候才产生结果,不是立即产生结果。12、
注意事项:
>生成器是只能遍历一次的。
>生成器是一类特殊的迭代器。123、
分类:
第一类:生成器函数:还是使用 def 定义函数,但是,使用yield而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。
如下案例加以说明:
# 菲波那切数列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中whileTrue:try:
x=next(f)
print("f:",x)except StopIteration as e:
print("生成器最后的返回值是:",e.value)break123456789101112131415161718、
第二类:生成器表达式:类似于列表
,只不过是把一对大括号[]变换为一对小括号()。但是,生成器表达式是按需产生一个生成器结果对象,要想拿到每一个元素,就需要循环遍历。
如下案例加以说明:
# 一个列表xiaoke=[2,3,4,5]# 生成器generator,类似于list,但是是把[]改为()gen=(a for ain xiaoke)foriin gen:
print(i)#结果是:2345# 为什么要使用生成器?因为效率。# 使用生成器表达式取代列表推导式可以同时节省 cpu 和 内存(RAM)。# 如果你构造一个列表(list)的目的仅仅是传递给别的函数,# 比如 传递给tuple()或者set(), 那就用生成器表达式替代吧!# 本案例是直接把列表转化为元组kk=tuple(a for a in xiaoke)
print(kk)#结果是:(2, 3, 4, 5)# python内置的一些函数,可以识别这是生成器表达式,外面有一对小括号,就是生成器result1=sum(a for a in range(3))
print(result1)# 列表推导式result2=sum([a for a in range(3)])
print(result2)

Q4:python 的迭代器为什么一定要实现

这是个和多态有关的问题,Python中关于迭代有两个概念,第一个是Iterable,第二个是Iterator,协议规定Iterable的__iter__方法会返回一个Iterator, Iterator的__next__方法(Python 2里是next)会返回下一个迭代对象,如果迭代结束则抛出StopIteration异常。
同时,Iterator自己也是一种Iterable,所以也需要实现Iterable的接口,也就是__iter__,这样在for当中两者都可以使用。Iterator的__iter__只需要返回自己就行了。这样,下面的代码就可以工作:
for i in my_list:
...
for i in iter(mylist):
...
for i in (v for v in mylist if v is not None):
...
Python中许多方法直接返回iterator,比如itertools里面的izip等方法,如果Iterator自己不是Iterable的话,就很不方便,需要先返回一个Iterable对象,再让Iterable返回Iterator。生成器表达式也是一个iterator,显然对于生成器表达式直接使用for是非常重要的。
那么为什么不只保留Iterator的接口而还需要设计Iterable呢?许多对象比如list、dict,是可以重复遍历的,甚至可以同时并发地进行遍历,通过__iter__每次返回一个独立的迭代器,就可以保证不同的迭代过程不会互相影响。而生成器表达式之类的结果往往是一次性的,不可以重复遍历,所以直接返回一个Iterator就好。让Iterator也实现Iterable的兼容就可以很灵活地选择返回哪一种。
总结来说Iterator实现的__iter__是为了兼容Iterable的接口,从而让Iterator成为Iterable的一种实现。
补充一下题主对于for的理解基本上是正确的,但仍然有一点点偏差:for为了兼容性其实有两种机制,如果对象有__iter__会使用迭代器,但是如果对象没有__iter__,但是实现了__getitem__,会改用下标迭代的方式。我们可以试一下:
>>> class NotIterable(object):...def __init__(self, baselist):...self._baselist = baselist...def __getitem__(self, index):...return self._baselist[index]...>>> t = NotIterable([1,2,3])>>> for i in t:...print i...123>>> iter(t)
当for发现没有__iter__但是有__getitem__的时候,会从0开始依次读取相应的下标,直到发生IndexError为止,这是一种旧的迭代协议。iter方法也会处理这种情况,在不存在__iter__的时候,返回一个下标迭代的iterator对象来代替。一个重要的例子是str,字符串就是没有__iter__接口的。

猜你喜欢

更多