파이썬 반복자에서 hasNext?


답변:


106

아니요, 그러한 방법은 없습니다. 반복 종료는 예외로 표시됩니다. 설명서를 참조하십시오 .


71
"허가보다 용서를 구하는 것이 더 쉽다."

118
"권한보다 용서를 구하는 것이 더 쉽습니다.": 반복자에게 다음 요소가 있는지 확인하는 것이 권한을 요구하지 않습니다. 다음 요소의 소비 여부를 테스트하려는 상황이 있습니다. unnext()호출하여 존재하는지 확인한 후 첫 번째 요소를 다시 넣는 방법 이 있으면 try catch 솔루션을 수락합니다 next().
조르지오

15
@ Giorgio, 생성하는 코드를 실행하지 않고 다른 요소가 있는지 여부를 알 수있는 방법이 없습니다 (생성기의 실행 여부를 모름 yield). 상점의 결과가 있음은 물론, 어려운 일이 아니다 어댑터를 작성하는 것입니다 next()및 제공 has_next()하고 move_next().
avakar

5
동일한 아이디어를 사용하여 hasNext()메소드 를 구현할 수 있습니다 (성공하면 true를 생성, 캐시 및 리턴하거나 실패하면 false를 리턴 함). 그리고 모두 hasNext()next()기본 공통에 달려 getNext()방법 및 캐시 항목을 선택합니다. 나는 next()그것을 제공하는 어댑터를 구현하기가 너무 쉬운 경우 왜 표준 라이브러리에 있지 않아야하는지 알지 못합니다.
Giorgio

3
@LarsH : 예를 들어 파일을 읽는 동안 읽을 수있는 반복자를 의미합니까? 나는 이것이 문제가 될 수 있음에 동의한다 ( 가설적인 파이썬 라이브러리뿐만 아니라 모든 라이브러리 제공 next()hasNext()방법에 영향을 미친다 ). 그래서 그래, next()hasNext()스캔 스트림의 내용에 의존하는 경우 까다로운 될 요소를 읽습니다.
Giorgio

239

StopIteration를 사용 하는 대안이 있습니다 next(iterator, default_value).

exapmle의 경우 :

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

따라서 None예외적 인 방법을 원하지 않으면 반복자 끝의 미리 지정된 값을 감지 하거나 다른 값을 감지 할 수 있습니다 .


70
"Sentinel"로 None을 사용하는 경우 반복자에 None이없는 것이 가장 좋습니다. 당신은 또한 할 수 sentinel = object()next(iterator, sentinel)와 테스트를 is.
sam boosalis

1
@ samboosalis 다음에 나는 unittest.mock.sentinel명시 적으로 next(a, sentinel.END_OF_ITERATION)다음 을 쓸 수있는 내장 객체를 사용 if next(...) == sentinel.END_OF_ITERATION
하려고합니다.

이것은 예외보다 더 예쁘다
datdinhquoc

문제는 이런 식으로 반복자에서 다음 값을 소비한다는 것입니다. Java의 hasNext는 다음 값을 사용하지 않습니다.
Alan Franzoni

39

당신이 정말로 경우 필요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

필요에 따라.

next(sel.it)내장으로 사용 하려면 Python 2.6 이상이 필요합니다. 이전 버전의 Python을 사용 self.it.next()하는 경우 대신 next(x)사용하십시오 (예제 사용법 과 유사 ). [[파이썬 2.6이 1 년 넘게 사용되어 왔기 때문에이 노트가 중복되었다고 생각할 수도 있습니다. 그러나 응답에 파이썬 2.6 기능을 사용할 때보 다 자주, 일부 주석가 또는 다른 사람들이 지적해야 할 의무가 있다고 생각합니다) 그것들 2.6 가지 기능이므로, 그런 의견을 한 번만 포기하려고합니다 ;-)]]


9
"자바의 참조 구현에서 알고리즘을 충실히 작성하는 것"은 has_next메소드 가 필요한 최악의 이유 입니다. 파이썬의 디자인은 filter배열에 주어진 술어와 일치하는 요소가 포함되어 있는지 확인하는 데 사용할 수 없습니다 . 파이썬 커뮤니티의 오만과 근시안은 엄청납니다.
Jonathan Cast

정답은 Java 코드에서 가져온 일부 디자인 패턴을 설명하기 위해 복사 한 것입니다.
madtyn

저는 Python3을 사용하고 있으며이 코드는 나에게TypeError: iter() returned non-iterator
madtyn

1
@JonathanCast 내가 확실하지 않습니다. 파이썬에서, 당신은 일반적으로 사용하는 것 mapany대신에 filter,하지만 당신은 사용할 수 있습니다 SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL또는 잊지 SENTINEL그냥 사용 try: except하고 잡아 StopIteration.
juanpa.arrivillaga

13

StopIteration에 대한 언급 외에도 Python "for"루프는 단순히 원하는 것을 수행합니다.

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

7

반복자 객체에서 __length_hint __ () 메소드를 시도하십시오.

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

5
나는 왜 지구상에서 파이썬이 모든 __ xxx __ 메소드를 가지고 있는지 궁금해했다. 그들은 너무 못생긴 것 같습니다.
mP.

6
합법적 인 질문! 일반적으로 내장 함수에 의해 노출되는 메소드의 구문입니다 (예 : len, 실제로 len 호출 ). 이러한 내장 함수는 length_hint에 존재하지 않지만 실제로 보류중인 제안입니다 (PEP424).
fulmicoton 2019

1
@mP. 이러한 기능은 때때로 필요하기 때문에 존재합니다. 그것들은 최후의 수단으로 간주되기 때문에 의도적으로 추한 것입니다.
Arne Babenhauserheide

좋아 __init__하고 __main__? Imho, 당신이 그것을 정당화하려고 시도하더라도 그것은 엉망입니다.
user1363990


4

,을 tee사용하여 반복자 가 가능하고 teed 반복자가 itertools.tee있는지 확인할 수 있습니다 StopIteration.


3

아니요. 가장 유사한 개념은 StopIteration 예외 일 가능성이 큽니다 .


10
파이썬이 제어 흐름에 예외를 사용하는 것은 무엇입니까? 꽤 잔소리가 들린다.
mP.

5
오른쪽 : 정상적인 제어 흐름을 정의하지 않고 오류를 처리하기 위해 예외를 사용해야합니다.
Giorgio


1

이것을 검색하게하는 유스 케이스는 다음과 같습니다.

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)

나에게 더 깨끗합니다. 분명히 유틸리티 클래스를 정의하여 문제를 해결할 수 있지만, 그 결과로 각각의 단점이있는 20 가지의 거의 동등한 대안이 확산되고 다른 해결 방법을 사용하는 코드를 재사용하려면 다음 중 하나를 수행해야합니다. 단일 응용 프로그램에서 거의 동등한 여러 항목을 사용하거나 동일한 접근 방식을 사용하기 위해 코드를 골라 다시 작성하십시오. '한 번하고 잘해라'는 맥심은 나쁘다.

또한, 반복자 자체는 예외를 제기해야하는지 확인하기 위해 내부 'hasnext'검사를 수행해야합니다. 그런 다음이 내부 검사는 숨겨져 있으므로 항목을 가져 오려고 시도하고 예외를 포착하고 처리 된 경우 처리기를 실행하여 테스트해야합니다. 이것은 숨기기 IMO를 숨길 필요가 없습니다.


1
이 사용 사례의 경우 itertools.cycle
eaglebrain을

0

권장되는 방법은 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()

-2

내 문제를 해결하는 방법은 지금까지 반복 된 객체 수를 유지하는 것입니다. 인스턴스 메소드 호출을 사용하여 세트를 반복하고 싶었습니다. 세트의 길이와 지금까지 계산 된 항목 수를 알았으므로 효과적으로 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

물론 예제는 장난감이지만 아이디어를 얻습니다. 생성기 등과 같이 iterable의 길이를 얻을 수있는 방법이없는 경우에는 작동하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.