jak wybrać tylko jeden element z generatora (w Pythonie)?

Mam funkcję generatora jak poniżej:

def myfunct():
  ...
  yield result

Zwyczajowym sposobem wywołania tej funkcji jest:

for r in myfunct():
  dostuff(r)

Moje pytanie, czy jest sposób, aby dostać tylko jeden element z generatora, kiedy tylko chcę? Na przykład, chciałbym zrobić coś w stylu:

while True:
  ...
  if something:
      my_element = pick_just_one_element(myfunct())
      dostuff(my_element)
  ...
Author: smci, 2011-01-20

5 answers

Tworzenie generatora za pomocą

g = myfunct()

Za każdym razem, gdy chcesz przedmiot, użyj

next(g)

(lub g.next() w Pythonie 2.5 lub poniżej).

Jeśli generator wyjdzie, podniesie się StopIteration. W razie potrzeby możesz przechwycić ten wyjątek lub użyć argumentu default do next():

next(g, default_value)
 189
Author: Sven Marnach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-12 09:31:32

Do wybrania tylko jednego elementu generatora użyj break w instrukcji for lub list(itertools.islice(gen, 1))

Według twojego przykładu (litteralnie) możesz zrobić tak:

while True:
  ...
  if something:
      for my_element in myfunct():
          dostuff(my_element)
          break
      else:
          do_generator_empty()
Jeśli chcesz " uzyskać tylko jeden element z generatora [once generated] kiedy tylko chcę" (przypuszczam, że 50% to pierwotna intencja i najczęstsza intencja), to:
gen = myfunct()
while True:
  ...
  if something:
      for my_element in gen:
          dostuff(my_element)
          break
      else:
          do_generator_empty()

W ten sposób można uniknąć jawnego użycia generator.next(), a obsługa końca wejścia nie wymaga (cryptic) StopIteration obsługa wyjątków lub dodatkowe porównywanie wartości domyślnych.

Sekcja else: z for jest potrzebna tylko, jeśli chcesz zrobić coś specjalnego w przypadku generatora końca.

Uwaga na next() / .next():

W Python3 metoda .next() została przemianowana na .__next__() nie bez powodu: jest uważana za niskopoziomową (PEP 3114). Przed Pythonem 2.6 wbudowana funkcja next() nie istniała. I nawet dyskutowano o przeniesieniu next() do operator modułu (co byłoby mądre), ze względu na rzadką potrzebę i wątpliwą inflację nazw.

Używanie next() bez domyślnego ustawienia jest nadal bardzo mało praktyczną praktyką-rzucanie tajemnicą StopIteration jak piorun znikąd w normalnym kodzie aplikacji otwarcie. I używanie {[9] } z domyślnym sentinel - który najlepiej powinien być jedyną opcją dla next() bezpośrednio w builtins - jest ograniczone i często daje powód do dziwnej nie pythonicznej logiki / czytelności.

Podsumowując: użycie next() powinno być bardzo rzadkie - jak użycie funkcje modułu {[15] }. Za pomocą for x in iterator , islice, list(iterator) i inne funkcje, które bezproblemowo akceptują Iteratory, są naturalnym sposobem korzystania z iteratorów na poziomie aplikacji - i to całkiem zawsze możliwe. next() jest niskopoziomowym, dodatkowym pojęciem, nieoczywistym - jak pokazuje kwestia tego wątku. Podczas gdy np. użycie break w {[3] } jest konwencjonalne.

 23
Author: kxr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-18 17:23:43

Nie wierzę, że jest wygodny sposób na pobranie dowolnej wartości z generatora. Generator dostarczy metodę next (), która sama się przemierzy, ale pełna sekwencja nie jest wytwarzana natychmiast, aby zapisać pamięć. To jest funkcjonalna różnica między generatorem a listą.

 2
Author: g.d.d.c,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-19 21:59:31
generator = myfunct()
while True:
   my_element = generator.next()

Upewnij się, że wyłapujesz wyjątek wyrzucony po wzięciu ostatniego elementu

 0
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-19 22:01:17

Wierzę, że jedynym sposobem jest uzyskanie listy z iteratora, a następnie uzyskanie elementu, który chcesz z tej listy.

l = list(myfunct())
l[4]
 -1
Author: keegan3d,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-19 21:58:52