在Python迭代器中具有hasNext?

问题:在Python迭代器中具有hasNext?

Python迭代器没有hasNext方法吗?

Haven’t Python iterators got a hasNext method?


回答 0

不,没有这样的方法。迭代结束由异常指示。请参阅文档

No, there is no such method. The end of iteration is indicated by an exception. See the documentation.


回答 1

StopIteration使用可以替代next(iterator, default_value)

例如:

>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None

因此None,如果您不想使用异常方法,则可以为迭代器的末尾检测或其他预先指定的值。

There’s an alternative to the StopIteration by using next(iterator, default_value).

For exapmle:

>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None

So you can detect for None or other pre-specified value for end of the iterator if you don’t want the exception way.


回答 2

如果你真的需要一个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功能,因此,我试图一次阻止所有此类评论;-)]]

If you really need a has-next functionality (because you’re just faithfully transcribing an algorithm from a reference implementation in Java, say, or because you’re writing a prototype that will need to be easily transcribed to Java when it’s finished), it’s easy to obtain it with a little wrapper class. For example:

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

now something like

x = hn_wrapper('ciao')
while x.hasnext(): print next(x)

emits

c
i
a
o

as required.

Note that the use of next(sel.it) as a built-in requires Python 2.6 or better; if you’re using an older version of Python, use self.it.next() instead (and similarly for next(x) in the example usage). [[You might reasonably think this note is redundant, since Python 2.6 has been around for over a year now — but more often than not when I use Python 2.6 features in a response, some commenter or other feels duty-bound to point out that they are 2.6 features, thus I’m trying to forestall such comments for once;-)]]


回答 3

除了提到StopIteration之外,Python的“ for”循环还可以满足您的要求:

>>> it = iter("hello")
>>> for i in it:
...     print i
...
h
e
l
l
o

In addition to all the mentions of StopIteration, the Python “for” loop simply does what you want:

>>> it = iter("hello")
>>> for i in it:
...     print i
...
h
e
l
l
o

回答 4

从任何迭代器对象尝试__length_hint __()方法:

iter(...).__length_hint__() > 0

Try the __length_hint__() method from any iterator object:

iter(...).__length_hint__() > 0

回答 5

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 "<stdin>", line 1, in <module>
StopIteration

hasNext somewhat translates to the StopIteration exception, e.g.:

>>> 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 "<stdin>", line 1, in <module>
StopIteration

回答 6

您可以tee使用itertools.tee和进行迭代,并检查StopIterationteed迭代器。

You can tee the iterator using, itertools.tee, and check for StopIteration on the teed iterator.


回答 7

否。最相似的概念很可能是StopIteration异常。

No. The most similar concept is most likely a StopIteration exception.


回答 8

我相信python只是具有next(),根据文档,它抛出一个异常是没有更多的元素。

http://docs.python.org/library/stdtypes.html#iterator-types

I believe python just has next() and according to the doc, it throws an exception is there are no more elements.

http://docs.python.org/library/stdtypes.html#iterator-types


回答 9

以下是促使我进行搜索的用例:

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。

The use case that lead me to search for this is the following

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 

where hasnext() is available, one could do

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)

which to me is cleaner. Obviously you can work around issues by defining utility classes, but what then happens is you have a proliferation of twenty-odd different almost-equivalent workarounds each with their quirks, and if you wish to reuse code that uses different workarounds, you have to either have multiple near-equivalent in your single application, or go around picking through and rewriting code to use the same approach. The ‘do it once and do it well’ maxim fails badly.

Furthermore, the iterator itself needs to have an internal ‘hasnext’ check to run to see if it needs to raise an exception. This internal check is then hidden so that it needs to be tested by trying to get an item, catching the exception and running the handler if thrown. This is unnecessary hiding IMO.


回答 10

建议的方法是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()

Suggested way is StopIteration. Please see Fibonacci example from 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()

回答 11

我解决问题的方法是保持到目前为止迭代对象的数量。我想使用对实例方法的调用来遍历集合。由于我知道集合的长度以及到目前为止已计算的项目数,因此我有效地有了一种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

当然,示例是一个玩具,但是您知道了。在无法获得迭代器长度的情况下(例如生成器等),这将不起作用。

The way I solved my problem is to keep the count of the number of objects iterated over, so far. I wanted to iterate over a set using calls to an instance method. Since I knew the length of the set, and the number of items counted so far, I effectively had an hasNext method.

A simple version of my code:

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

Of course, the example is a toy one, but you get the idea. This won’t work in cases where there is no way to get the length of the iterable, like a generator etc.