[python] 생성기가 처음부터 비어 있는지 어떻게 알 수 있습니까?

발전기에 peek,, hasNext등의 품목이없는 경우 간단한 테스트 방법이 isEmpty있습니까?



답변

귀하의 질문에 대한 간단한 답변 : 아니오, 간단한 방법은 없습니다. 해결 방법이 많이 있습니다.

생성기가 무엇인지에 따라 간단한 방법이 없어야 합니다 . 시퀀스를 메모리에 유지하지 않고 일련의 값을 출력하는 방법 . 따라서 뒤로 순회가 없습니다.

원하는 경우 has_next 함수를 작성하거나 멋진 데코레이터로 메소드로 생성기에 쓸 수도 있습니다.


답변

암시:

def peek(iterable):
    try:
        first = next(iterable)
    except StopIteration:
        return None
    return first, itertools.chain([first], iterable)

용법:

res = peek(mysequence)
if res is None:
    # sequence is empty.  Do stuff.
else:
    first, mysequence = res
    # Do something with first, maybe?
    # Then iterate over the sequence:
    for element in mysequence:
        # etc.


답변

간단한 방법은 생성기가 소진되거나 비어있는 경우 next ()에 선택적 매개 변수를 사용하는 것입니다. 예를 들면 다음과 같습니다.

iterable = some_generator()

_exhausted = object()

if next(iterable, _exhausted) == _exhausted:
    print('generator is empty')

편집 : mehtunguh의 의견에서 지적 된 문제가 수정되었습니다.


답변

next(generator, None) is not None

또는 대체 None하지만 당신이 알고있는 값 은 발전기에 없습니다 .

편집 : 예, 생성기에서 1 개의 항목을 건너 뜁니다. 그러나 종종 유효성 검사 목적으로 만 생성기가 비어 있는지 확인한 다음 실제로 사용하지는 않습니다. 그렇지 않으면 나는 다음과 같은 것을한다 :

def foo(self):
    if next(self.my_generator(), None) is None:
        raise Exception("Not initiated")

    for x in self.my_generator():
        ...

그게 당신의 경우이 작품이며, 발전기는 A로부터 오는 기능 처럼 generator().


답변

IMHO의 최선의 방법은 특별한 테스트를 피하는 것입니다. 대부분의 시간, 발전기의 사용 이다 테스트는 :

thing_generated = False

# Nothing is lost here. if nothing is generated, 
# the for block is not executed. Often, that's the only check
# you need to do. This can be done in the course of doing
# the work you wanted to do anyway on the generated output.
for thing in my_generator():
    thing_generated = True
    do_work(thing)

충분하지 않은 경우에도 명시 적 테스트를 수행 할 수 있습니다. 이 시점 thing에서 마지막으로 생성 된 값이 포함됩니다. 아무것도 생성되지 않은 경우 변수를 아직 정의하지 않은 경우 정의되지 않습니다. 의 값을 확인할 수 thing있지만 약간 신뢰할 수 없습니다. 대신 블록 내에 플래그를 설정하고 나중에 확인하십시오.

if not thing_generated:
    print "Avast, ye scurvy dog!"


답변

나는 나 자신을 사용하지 않을 것이라고, 특히 한 두 번째 솔루션을 제공 싫지만, 당신은 절대적 경우 이 작업을 수행하고 다른 답변에서와 같이 발전기를 소비하지 :

def do_something_with_item(item):
    print item

empty_marker = object()

try:
     first_item = my_generator.next()
except StopIteration:
     print 'The generator was empty'
     first_item = empty_marker

if first_item is not empty_marker:
    do_something_with_item(first_item)
    for item in my_generator:
        do_something_with_item(item)

이제는이 솔루션이 마음에 들지 않습니다. 왜냐하면 이것이 발전기가 사용되는 방식이 아니라고 믿기 때문입니다.


답변

나는이 게시물이 지금 5 세라는 것을 알고 있지만, 이것을하는 관용적 인 방법을 찾고있는 동안 그것을 발견했지만 내 솔루션이 게시되지 않았습니다. 후손을 위해 :

import itertools

def get_generator():
    """
    Returns (bool, generator) where bool is true iff the generator is not empty.
    """
    gen = (i for i in [0, 1, 2, 3, 4])
    a, b = itertools.tee(gen)
    try:
        a.next()
    except StopIteration:
        return (False, b)
    return (True, b)

물론, 많은 주석가들이 지적 하겠지만, 이것은 해키이며 특정 제한된 상황 (예 : 발전기가 부작용이없는 곳)에서만 작동합니다. YMMV.