Python迭代器有has_next方法吗?


当前回答

我相信python只有next(),根据文档,如果没有更多的元素,它就会抛出异常。

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

其他回答

如果您确实需要一个has-next功能,那么使用一个小包装器类很容易获得它。例如:

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

是必需的。

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;-)]]

===

对于Python3,您将进行以下更改:

from collections.abc import Iterator  # since python 3.3 Iterator is here

class hn_wrapper(Iterator):  # need to subclass Iterator rather than object
  def __init__(self, it):
    self.it = iter(it)
    self._hasnext = None
    
  def __iter__(self): 
    return self
  
  def __next__(self):        # __next__ vs next in python 2
    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

不。最类似的概念很可能是StopIteration异常。

非常有趣的问题,但是这个“hasnext”的设计已经放进了leetcode: https://leetcode.com/problems/iterator-for-combination/

这是我的实现:

class CombinationIterator:

def __init__(self, characters: str, combinationLength: int):
    from itertools import combinations
    from collections import deque
    self.iter = combinations(characters, combinationLength)
    self.res = deque()


def next(self) -> str:
    if len(self.res) == 0:
        return ''.join(next(self.iter))
    else:
        return ''.join(self.res.pop())


def hasNext(self) -> bool:
    try:
        self.res.insert(0, next(self.iter))
        return True
    except:
        return len(self.res) > 0

不,没有这样的方法。迭代的结束是由StopIteration表示的(更多信息在这里)。


这遵循了python原则EAFP(请求原谅比请求许可更容易)。has_next方法将遵循LBYL原则(三思而后行),并与python的核心原则相矛盾。

这篇有趣的文章更详细地解释了这两个概念。

我认为当你想要某种has_next功能时,有一些有效的用例,在这种情况下,你应该用定义了has_next的迭代器来装饰迭代器。

结合这个问题的答案的概念,这里是我的实现,这对我来说是一个很好的简洁的解决方案(python 3.9):

_EMPTY_BUF = object()


class BufferedIterator(Iterator[_T]):
    def __init__(self, real_it: Iterator[_T]):
        self._real_it = real_it
        self._buf = next(self._real_it, _EMPTY_BUF)

    def has_next(self):
        return self._buf is not _EMPTY_BUF

    def __next__(self) -> _T_co:
        v = self._buf
        self._buf = next(self._real_it, _EMPTY_BUF)
        if v is _EMPTY_BUF:
            raise StopIteration()
        return v

主要的区别是has_next只是一个布尔表达式,也处理None值的迭代器。

将此添加到这里的测试和示例使用的要点。