- 主题:关于for in的简单实现
下面能够实现循环, 但是, 有个小问题, 就是循环完毕, 按照规范__next__ 应该抛出StopIteration
但奇怪的是for in 并没有对这个异常做处理, 而是继续抛出来了, 是这个异常不对吗?
如果, 去掉这个raise, 只是简单返回好像就不出错了。
from abc import ABC
class TestForin(ABC):
def __init__(self):
self.for_in = range(1,5)
pass
def __iter__(self):
return self.__next__()
def __next__(self):
for i in self.for_in:
yield i
else:
raise StopIteration()
if __name__ == "__main__":
f = TestForin()
for x in f:
print(x)
--
FROM 124.126.0.*
你实现了一个错误的__iter__方法,它应该返回一个迭代器对象而不是调用__next__。
其次,你在实现__next__时使用了yield关键字,这意味着它实际上是一个生成器函数,而不是__next__方法的正确实现。
next直接返回值就行,不用实现iter
【 在 poggy 的大作中提到: 】
:
: 下面能够实现循环, 但是, 有个小问题, 就是循环完毕, 按照规范__next__ 应该抛出StopIteration
: 但奇怪的是for in 并没有对这个异常做处理, 而是继续抛出来了, 是这个异常不对吗?
: 如果, 去掉这个raise, 只是简单返回好像就不出错了。
:
#发自zSMTH@CDU.MP
--
FROM 171.120.158.*
【 在 VincentGe 的大作中提到: 】
: 你实现了一个错误的__iter__方法,它应该返回一个迭代器对象而不是调用__next__。
: 其次,你在实现__next__时使用了yield关键字,这意味着它实际上是一个生成器函数,而不是__next__方法的正确实现。
: next直接返回值就行,不用实现iter
: ...................
您需要再多学习学习基础知识,:)
生成器函数本身就是一种特殊的迭代器。
我大概知道怎么回事了, 只需要把抛异常的两行代码屏蔽掉就行了。
python的实现, 大概是, for in 使用了迭代函数本身会反复调用迭代函数。
from abc import ABC
class TestForin(ABC):
def __init__(self):
self.for_in = range(1,5)
pass
def __iter__(self):
return self.__next__()
def __next__(self):
for i in self.for_in:
yield i
#else:
# raise StopIteration()
if __name__ == "__main__":
f = TestForin()
for x in f:
print(x)
--
修改:poggy FROM 124.126.0.*
FROM 124.126.0.*
【 在 poggy 的大作中提到: 】
:
: 您需要再多学习学习基础知识,:)
: 生成器函数本身就是一种特殊的迭代器。
: ...................
下面是一个不用生成函数版本的实现。
from abc import ABC
class TestForin(ABC):
def __init__(self):
self.for_in = range(1,5)
def __iter__(self):
self.iter_pos = len(self.for_in)*(-1)
return self
def __next__(self):
if self.iter_pos < 0:
ret = self.for_in[self.iter_pos]
self.iter_pos += 1
return ret
else:
raise StopIteration()
if __name__ == "__main__":
f = TestForin()
for x in f:
print(x)
--
FROM 124.126.0.*
【 在 poggy 的大作中提到: 】
:
: 您需要再多学习学习基础知识,:)
: 生成器函数本身就是一种特殊的迭代器。
: ...................
目前测试的实验结果,
是可以在__iter__返回一个迭代函数, 迭代函数的名字是任意的, 看来for的实现,
会反复调用这个迭代函数。知道这个迭代函数不再以yield返回, for就会正常终止了,
这里面for似乎不再处理StopIteration 这个异常。
--
修改:poggy FROM 124.126.0.*
FROM 124.126.0.*
我建议你阅读Python文档中的术语表。
对于你给出的第二段代码,它是一个标准的迭代器其中iter返回self,next被反复调用返回值。
包含yield的函数被称为生成器,其返回值是生成器迭代器。其中不应当引发任何异常,如果你引发stopiteration,则会产生一个Runtime Error。还有for else 很少用,建议不要使用。
第一个例子中你的用法是错误用法,它没有实现迭代器,如果其他人调用next(obj)不能得到期望的结果。
我建议你重新学习基础内容
【 在 poggy 的大作中提到: 】
:
: 【 在 poggy 的大作中提到: 】
: :
: : 您需要再多学习学习基础知识,:)
: : 生成器函数本身就是一种特殊的迭代器。
#发自zSMTH@CDU.MP
--
FROM 171.120.158.*
【 在 VincentGe 的大作中提到: 】
: 我建议你阅读Python文档中的术语表。
: 对于你给出的第二段代码,它是一个标准的迭代器其中iter返回self,next被反复调用返回值。
: 包含yield的函数被称为生成器,其返回值是生成器迭代器。其中不应当引发任何异常,如果你引发stopiteration,则会产生一个Runtime Error。还有for else 很少用,建议不要使用。
: ...................
你还是没搞清, 什么是可迭代对象, 什么是迭代器, 什么是生成器。
你说的next是可迭代对象, 的接口, 和iterator是是两个东西。
for in 可以使用迭代器实现, 但是, 使用生成函数一样可以实现。
--
FROM 124.126.0.*
【 在 VincentGe 的大作中提到: 】
: 你实现了一个错误的__iter__方法,它应该返回一个迭代器对象而不是调用__next__。
: 其次,你在实现__next__时使用了yield关键字,这意味着它实际上是一个生成器函数,而不是__next__方法的正确实现。
: next直接返回值就行,不用实现iter
: ...................
我到这里是来讨论问题的, 我一开始标题就告知, 在讨论 for in的实现问题,
__iter__ 当然可以返回迭代器对象, 而且, 返回迭代器是for in的大多数实现,
但是, 如果你仔细看规范, for 循环并不要求是迭代器对象,
而是更宽泛的, Iterable, 而且, 使用生成函数, 自由度更高。
--
FROM 124.126.0.*
【 在 poggy 的大作中提到: 】
:
: 【 在 VincentGe 的大作中提到: 】
: : 我建议你阅读Python文档中的术语表。
: : 对于你给出的第二段代码,它是一个标准的迭代器其中iter返回self,next被反复调用返回值。
: : 包含yield的函数被称为生成器,其返回值是生成器迭代器。其中不应当引发任何异常,如果你引发stopiteration,则会产生一个Runtime Error。还有for else 很少用,建议不要使用。
我认为我很清楚,朋友,是你在这方面有问题。
可迭代对象不一定是迭代器,一个迭代器对象要求__iter__必须返回自身,实现了__next__对象才能是迭代器。生成器函数的返回值是生成器迭代器。
你错误的使用了__next__方法,你的第一方案会导致异常,请你重复调用next,你会发现你的迭代器无法终止。
另我建议你将你的内容置于上方,否则我的客户端无法正确引用你的回答
#发自zSMTH@CDU.MP
--
FROM 171.120.158.*
我并无恶意,我也是来讨论问题。
for in 对应的是可迭代对象,它会调用__iter__,得到一个可迭代对象,如果这个对象是迭代器,它会调用迭代器的 __next__方法,系统会自行处理Stop iteration异常。
也就是说,__next__是用来实现迭代器的,你将__next__写为一个生成器后,得到的是一个生成器迭代器,在生成器迭代器里引发Stopiteration 会产生一个 RuntimerError异常
: ...................
我到这里是来讨论问题的, 我一开始标题就告知, 在讨论 for in的实现问题,
__iter__ 当然可以返回迭代器对象, 而且, 返回迭代器是for in的大多数实现,
但是, 如果你仔细看规范, for 循环并不要求是迭代器对象,
而是更宽泛的, Iterable, 而且, 使用生成函数, 自由度更高。
#发自zSMTH@CDU.MP
--
FROM 171.120.158.*