как выбрать только один элемент из генератора (в Python)?


у меня есть функция генератора следующим образом:

def myfunct():
  ...
  yield result

обычный способ вызова этой функции будет:

for r in myfunct():
  dostuff(r)

мой вопрос, есть ли способ получить только один элемент из генератора, когда мне нравится? Например, я хотел бы сделать что-то вроде:

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

5 ответов:

создать генератор, с помощью

g = myfunct()

каждый раз, когда вы хотели бы товар, использовать

next(g)

(или g.next() в Python 2.5 или ниже).

если генератор выйдет, он поднимет StopIteration. Вы можете либо поймать это исключение, если это необходимо, либо использовать до next():

next(g, default_value)

для выбора только одного элемента генератора используйте 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 обработка исключений или дополнительные сравнения значений по умолчанию.

The else: на for раздел заявления необходим только если вы хотите сделать что-то особенное в случае конца генератора.

Примечание next()/.next():

в Python3 the .next() метод был переименован в .__next__() по уважительной причине: его считают низкоуровневым (PEP 3114). Перед Python 2.6 встроенная функция next() не существовало. И это даже обсуждалось, чтобы двигаться next() до operator модуль (что было бы разумно), из-за его редкой необходимости и сомнительной инфляции встроенных имен.

используя next() без дефолта по-прежнему очень низкоуровневая практика-бросание загадочного StopIteration как гром среди ясного неба в нормальном коде приложения открыто. И используя next() С sentinel по умолчанию - который лучше всего должен быть единственным вариантом для next() непосредственно в builtins - ограничен и часто дает повод нечетные номера-обновления логики/readablity.

итог: использование next () должно быть очень редким - как использование функций operator модуль. Используя for x in iterator,islice,list(iterator) и другие функции, легко принимающие итератор, - это естественный способ использования итераторов на уровне приложения-и вполне всегда возможно. next() является низкоуровневым, дополнительным понятием, неочевидным-как показывает вопрос этой темы. В то время как, например, с помощью break на for - это обычный.

Я не верю, что есть удобный способ получить произвольное значение из генератора. Генератор предоставит метод next () для прохождения себя, но полная последовательность не создается сразу для сохранения памяти. Это функциональное различие между генератором и списком.

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

убедитесь, что вы поймали исключение, возникшее после того, как последний элемент был взят

Я считаю, что единственный способ, чтобы получить список из итератора, а затем получить элемент, который вы хотите из списка.

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