Python迭代器是否没有hasNext方法?
相关:我如何知道一开始发电机是否为空?
使用next(iterator, default_value)可以替代StopIteration。
例如:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
因此,如果您不想使用异常方法,则可以检测到None或迭代器末尾的其他预先指定的值。
如果将"无"用作"前哨",则最好确保迭代器没有任何"无"。您还可以执行sentinel = object()和next(iterator, sentinel)并使用is进行测试。
在@samboosalis之后,我宁愿使用内置的unittest.mock.sentinel对象,该对象允许您先编写显式的next(a, sentinel.END_OF_ITERATION),然后编写if next(...) == sentinel.END_OF_ITERATION
这比例外还漂亮
不,没有这样的方法。迭代结束由异常指示。请参阅文档。
"请求宽恕比允许容易。"
"请求宽容比允许要容易。":检查迭代器是否具有下一个元素并不要求允许。在某些情况下,您想测试下一个元素的存在而不消耗它。如果有unnext()方法可以通过调用next()检查第一个元素是否存在,那么我将接受尝试捕获解决方案。
@Giorgio,如果不执行另一个生成元素的代码,就无法知道另一个元素是否存在(您不知道生成器是否将执行yield)。当然,编写存储next()结果并提供has_next()和move_next()的适配器并不难。
可以使用相同的思想来实现hasNext()方法(在成功时产生,缓存并返回true,或者在失败时返回false)。然后hasNext()和next()都将依赖于通用的基础getNext()方法和缓存项。如果真的很容易实现提供它的适配器,我真的不明白为什么next()不应该出现在标准库中。
@乔治,我不明白你在说什么。 next是标准;它抛出序列的末尾。适配器可以使用此next并缓存该值。没有人说它不应该在标准库中。我猜只是没有需求。
我了解,我认为不将其纳入标准的动机是技术上的。正如您所说,可能对它的需求根本不够。
@Giorgio,我大体上同意你的观点,尽管:如果hasNext()在标准库中,则所有迭代器都将被强制实现(或者如果不支持它,则返回错误……在那里进行设计决策)。对于某些迭代器而言,这些迭代器对时间的上下文高度敏感,因此迭代器中第一项的值可以在对hasNext()的调用与对next()的调用之间(可能在不同的模块中)改变,结果next()返回一个过时的值。我不知道,只是想看看争论的双方。我同意这样做会有帮助。
@LarsH:您的意思是例如从文件读取的迭代器可以在读取文件时更改?我同意这可能是一个问题(这会影响提供next()和hasNext()方法的任何库,而不仅仅是一个假设的Python库)。所以是的,如果要扫描的流的内容取决于何时读取元素,则next()和hasNext()会变得很棘手。
@Giorgio:是的,这就是我在想的一个例子。因此,当Python glob库的iglob()返回一个迭代器时,我们会遇到这个问题:一个迭代器,其返回值对时间敏感(即不是纯函数)。那么这是否意味着不应将诸如I / O之类的不纯函数作为迭代器使用?设计决策...
您都可以通过两种方式寻求许可。这不是C;)我想没有has_next(),因为它会使事情变得复杂。
python通常缺乏基本语言用法的结构,这些结构迫使诸如捕获异常之类的事情发生。然后,它或多或少地被认为是正确的做事方式而变得合理。另一个是缺少do .. while
如果您确实需要has-next功能(例如,因为您只是忠实地从Java的参考实现中转录算法,或者是因为您正在编写原型,则需要在完成后轻松将其转录为Java),只需使用一些包装器类就可以轻松获得它。例如:
class hn_wrapper(object):
def __init__(self, it):
self.it = iter(it)
self._hasnext = None
def __iter__(self): return self
def next(self):
if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext = None
return result
def hasnext(self):
if self._hasnext is None:
try: self._thenext = next(self.it)
except StopIteration: self._hasnext = False
else: self._hasnext = True
return self._hasnext
现在像
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
发出
c
i
a
o
按要求。
请注意,使用next(sel.it)作为内置函数需要Python 2.6或更高版本;如果您使用的是旧版本的Python,请改为使用self.it.next()(在示例用法中对于next(x)类似)。 [[[您可能会合理地认为此注释是多余的,因为Python 2.6已经存在一年多了-但是当我在响应中使用Python 2.6功能时,很多评论者或其他人有责任指出它们是2.6功能,因此,我尝试一次阻止此类评论;-)]]
"忠实地从Java参考实现中转录算法"是需要has_next方法的最糟糕原因。 Python的设计使得不可能使用filter来检查数组是否包含与给定谓词匹配的元素。 Python社区的傲慢和短视令人震惊。
很好的答案,我将其复制为说明从Java代码中获取的某些设计模式
我使用Python3,这段代码给了我TypeError: iter() returned non-iterator
@JonathanCast不确定我是否遵循。在Python中,通常使用map和any而不是filter,但是可以使用SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL或忘记SENTINEL而只使用try: except并捕获StopIteration。
除了提到StopIteration之外,Python的" for"循环还可以满足您的要求:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
从任何迭代器对象尝试__length_hint __()方法:
iter(...).__length_hint__() > 0
我一直想知道为什么python拥有所有这些__ xxx __方法?他们看起来很丑。
正当问题!通常,它是内置函数公开的方法的语法(例如len,实际上是在调用len)。对于length_hint不存在这样的内置函数,但实际上它是一个挂起的建议(PEP424)。
@mP。这些功能在那里,因为有时需要它们。它们故意是丑陋的,因为它们被认为是不得已的方法:如果使用它们,您将知道自己做的是非Python的并且有潜在危险的操作(该操作可能随时停止工作)。
像__init__和__main__一样?恕我直言,无论您试图为其辩护,都有些混乱。
hasNext在某种程度上转换为StopIteration异常,例如:
>>> it = iter("hello")
>>> it.next()
'h'
>>> it.next()
'e'
>>> it.next()
'l'
>>> it.next()
'l'
>>> it.next()
'o'
>>> it.next()
Traceback (most recent call last):
File"", line 1, in
StopIteration
StopIteration文档:http://docs.python.org/library/exceptions.html#exceptions.StopIteration
关于python中的迭代器和生成器的一些文章:http://www.ibm.com/developerworks/library/l-pycon.html
您可以使用itertools.tee tee迭代器,并在teed迭代器上检查StopIteration。
否。最相似的概念很可能是StopIteration异常。
哪些Python将异常用于控制流?听起来不错。
正确:应该使用异常来处理错误,而不是定义正常的控制流程。
我相信python只是具有next(),根据文档,它抛出一个异常是没有更多的元素。
http://docs.python.org/library/stdtypes.html#iterator-types
以下是促使我进行搜索的用例:
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
try:
x = next(fi)
except StopIteration:
fi = iter(f)
x = next(fi)
self.a[i] = x
在hasnext()可用的地方,一个可以做
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
if not hasnext(fi):
fi = iter(f) # restart
self.a[i] = next(fi)
对我来说更干净显然,您可以通过定义实用程序类来解决问题,但是随后发生的事情是,您有二十多种不同的,几乎等同的解决方法,每个方法都有其怪癖,并且,如果您想重用使用不同解决方法的代码,则必须在您的单个应用程序中具有多个几乎相等的值,或者四处浏览并重写代码以使用相同的方法。"一次做就做好"的格言非常失败。
此外,迭代器本身需要进行内部" hasnext"检查,以查看是否需要引发异常。然后隐藏此内部检查,以便需要通过尝试获取项目,捕获异常并在抛出异常时运行处理程序来对其进行测试。这是不必要的隐藏IMO。
对于此用例,可以使用itertools.cycle
建议的方法是StopIteration。
请从tutorialspoint看斐波那契示例
#!usr/bin/python3
import sys
def fibonacci(n): #generator function
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(5) #f is iterator object
while True:
try:
print (next(f), end="")
except StopIteration:
sys.exit()
解决此类问题的好方法是检查dir(object / method / iterator / type / class / ...)中的内容
您会看到dir(iterator)返回__length_hint__
iterator.__length_hint__()为正,直到迭代结束。
而已。
不能保证__length_hint__是准确的:python.org/dev/peps/pep-0424。
我解决问题的方法是保持到目前为止迭代对象的数量。我想使用对实例方法的调用来遍历一个集合。由于我知道集合的长度以及到目前为止已计算的项目数,因此有效地使用了hasNext方法。
我的代码的简单版本:
class Iterator:
# s is a string, say
def __init__(self, s):
self.s = set(list(s))
self.done = False
self.iter = iter(s)
self.charCount = 0
def next(self):
if self.done:
return None
self.char = next(self.iter)
self.charCount += 1
self.done = (self.charCount < len(self.s))
return self.char
def hasMore(self):
return not self.done
当然,示例是一个玩具,但是您知道了。在无法获取迭代器长度的情况下(例如生成器等),这将不起作用。