발전기에서 하나의 항목 만 선택하는 방법은 무엇입니까?


213

다음과 같은 생성기 기능이 있습니다.

def myfunct():
  ...
  yield result

이 함수를 호출하는 일반적인 방법은 다음과 같습니다.

for r in myfunct():
  dostuff(r)

내 질문, 내가 좋아할 때마다 발전기에서 하나의 요소를 얻는 방법이 있습니까? 예를 들어 다음과 같은 작업을 수행하고 싶습니다.

while True:
  ...
  if something:
      my_element = pick_just_one_element(myfunct())
      dostuff(my_element)
  ...

답변:


304

를 사용하여 생성기 생성

g = myfunct()

아이템을 원할 때마다

next(g)

(또는 g.next()Python 2.5 이하).

생성기가 종료되면을 발생 StopIteration시킵니다. 필요한 경우이 예외를 포착하거나 default인수를 사용하여 다음을 수행 할 수 있습니다 next().

next(g, default_value)

4
g의 마지막 항목이 제공된 후 g.next ()를 사용하려고 할 때만 StopIteration이 발생합니다.
Wilduck

26
next(gen, default)StopIteration예외 를 피하기 위해 사용될 수도 있습니다 . 예를 들어 next(g, None), 문자열 생성기의 경우 반복이 완료된 후 문자열을 생성하거나 없음을 생성합니다.
Attila

8
파이썬 3000 년) (다음은 (__) __next입니다
조나단 볼드윈

27
@JonathanBaldwin : 귀하의 의견은 다소 오해의 소지가 있습니다. 파이썬 3에서는 내 대답에 주어진 두 번째 구문을 사용합니다 next(g). 이것은 내부적으로 호출 할 것이다 g.__next__(), 그러나 당신은 정말 당신이 보통 그 상관하지 않는 것처럼, 그것에 대해 걱정하지 않아도 len(a)내부적으로 호출 a.__len__().
Sven Marnach

14
나는 더 분명 했어야했다. g.next()이다 g.__next__()py3k에. 내장 next(iterator)은 Python 2.6부터 사용되었으며 모든 새로운 Python 코드에서 사용해야하는 것이기 때문에 py <= 2.5를 지원해야하는 경우 역 구현하기가 쉽지 않습니다.
Jonathan Baldwin

29

명령문 break에서 생성기 사용 요소 중 하나만 선택 for하거나list(itertools.islice(gen, 1))

귀하의 예에 따르면 (문자 그대로) 다음과 같은 작업을 수행 할 수 있습니다.

while True:
  ...
  if something:
      for my_element in myfunct():
          dostuff(my_element)
          break
      else:
          do_generator_empty()

" 내가 원할 때마다 " 한 번 생성 된] 생성기 에서 하나의 요소 만 얻으려면 "(원래 의도와 가장 일반적인 의도는 50 %라고 가정)

gen = myfunct()
while True:
  ...
  if something:
      for my_element in gen:
          dostuff(my_element)
          break
      else:
          do_generator_empty()

이런 식으로 명시적인 사용을 generator.next()피할 수 있으며 입력 끝 처리에는 (암호화)가 필요하지 않습니다StopIteration 예외적 인 처리 또는 추가 기본값 비교가 .

그만큼 else:for 당신이 끝 발전기의 경우에는 뭔가 특별한 작업을 수행하려면 문 섹션에만 필요합니다.

에 참고 next()/.next() :

Python3에서이 .next()방법의 이름은 .__next__()낮은 수준 (PEP 3114)으로 변경되었습니다. 파이썬 2.6 이전에는 내장 함수 next()가 존재하지 않았습니다. 그리고 심지어 움직이기로 논의되었습니다next()operator 드문 필요와 내장 이름의 의심스러운 인플레이션으로 인해 모듈로 현명 되었습니다.

next()기본값없이 사용하는 것은 여전히 ​​낮은 수준의 연습 StopIteration입니다. 일반 응용 프로그램 코드에서 파란색으로 볼트와 같은 암호를 공개적으로 공개하십시오. next()기본 센티넬과 함께 사용 하는 것이 가장 좋습니다.next() .builtins - .

결론 : next ()를 사용하는 것은 operator모듈의 함수를 사용하는 것과 같이 매우 드 should니다 . 사용 for x in iterator, islice, list(iterator)아주 항상 가능하고 - 그리고 다른 기능이 원활 반복자를 받아들이는 것은 응용 프로그램 수준에 반복자를 사용하는 자연적인 방법입니다. next()이 스레드의 질문에서 알 수 있듯이 저수준의 추가 개념은 명백합니다. 예를 들어 breakin을 사용 하는 for것이 일반적입니다.


8
이것은 목록 결과의 첫 번째 요소를 얻는 데 너무 많은 작업입니다. 종종 나는 게으르지 않아도되지만 py3에서 선택할 수는 없습니다. 비슷한 것이 mySeq.head없습니까?
javadba

2

발전기에서 임의의 값을 검색하는 편리한 방법이 없다고 생각합니다. 생성기는 자체를 통과하는 next () 메소드를 제공하지만 메모리를 절약하기 위해 전체 시퀀스가 ​​즉시 생성되지는 않습니다. 그것은 생성기와리스트의 기능적 차이입니다.


1

Python3에 대한 완전한 작업 예제를 위해이 답변을 스캔하는 사람들은 여기에 있습니다.

def numgen():
    x = 1000
    while True:
        x += 1
        yield x

nums = numgen() # because it must be the _same_ generator

for n in range(3):
    numnext = next(nums)
    print(numnext)

출력 :

1001
1002
1003

1

제너레이터는 이터레이터를 생성하는 함수입니다. 따라서 반복자 인스턴스가 있으면 next () 를 사용 하여 반복자에서 다음 항목을 가져옵니다. 예를 들어 next () 함수를 사용하여 첫 번째 항목을 가져오고 나중에 사용 for in하여 나머지 항목을 처리하십시오.

# create new instance of iterator by calling a generator function
items = generator_function()

# fetch and print first item
first = next(items)
print('first item:', first)

# process remaining items:
for item in items:
    print('next item:', item)

0
generator = myfunct()
while True:
   my_element = generator.next()

마지막 요소를 가져온 후에 발생하는 예외를 잡아라


Python 3에는 유효하지 않습니다. . kxr 답변을 .
clacke

2
파이썬 3의 경우 "generator.next ()"를 "next (generator)"로
바꾸

-3

유일한 방법은 반복자에서 목록을 얻은 다음 해당 목록에서 원하는 요소를 얻는 것입니다.

l = list(myfunct())
l[4]

스벤의 대답이 더 좋을지 모르지만 필요에 더 잘 맞도록 여기에 남겨 두겠습니다.
keegan3

26
이 작업을 수행하기 전에 유한 발전기가 있는지 확인하십시오.
세스

6
죄송합니다. 이터레이터의 길이는 복잡하지만 문제는 분명히 O (1)입니다.
yo

1
생성기에서 너무 많은 메모리와 프로세스를 낭비합니다! 또한 @Seth가 앞에서 언급했듯이 생성기는 언제 중지해야하는지 보장하지 않습니다.
pylover

이것은 분명히 하지 (경우 또는 가장 좋은 방법 유일한 방법은 myfunct()당신이 사용할 수 있기 때문에 값의 큰 숫자를 생성) 내장 함수 next다음 생성 된 값을 얻을 수 있습니다.
HelloGoodbye
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.