Есть ли встроенный способ конвертировать функцию без аргументов в генератор? - PullRequest
3 голосов
/ 07 февраля 2020

Предположим, у меня есть функция, которая производит значение, скажем:

import random

def f():
    return random.randint(1,10)

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

def g(n):
    while True:
        if n == k:
            return
        else:
            print("x")
            return

Использование оператора while True кажется не элегантным, и я бы предпочел использовать генератор, например, следующий:

def f2():
    while True:
        yield random.randint(1,10)

def g(n):
    for k in f2():
        if n == k:
            return
        else:
            print("x")

Однако это просто толкает проблему while True в определение f(). Есть ли встроенная функция, которая принимает функцию и возвращает генератор, например, следующий псевдокод:

def make_generator_from_function(f):
    def gen_f():
        while True:
            yield f()
    return gen_f

def g3(n):
    for k in make_generator_from_function(f):
        if n == k:
            return
        else:
            print("x")

Ответы [ 2 ]

3 голосов
/ 07 февраля 2020

Встроенная функция iter может сделать это:

Если задан второй аргумент sentinel, тогда object должен быть вызываемым объект. Созданный в этом случае итератор будет вызывать object без аргументов для каждого вызова его __next__() метода; если возвращаемое значение равно sentinel, StopIteration будет увеличено, в противном случае будет возвращено значение.

Пример: число 5 является часовым, поэтому итерация будет остановлена когда random.randint(1, 10) возвращает 5.

>>> import random
>>> def f():
...     return random.randint(1, 10)
... 
>>> iter(f, 5)
<callable_iterator object at 0x7f3e11becc50>
>>> for x in iter(f, 5):
...     print(x)
... 
3
3
1
10
9
7
9
6
10
10
9
7
7
3
2
7
2
3
1 голос
/ 07 февраля 2020

Вы можете itertools.repeat() в выражении генератора, например:

Код:

import itertools as it
import random

for i in (random.randint(1, 10) for _ in it.repeat(1)):
    if i == 5:
        break
    print(i)

Результаты:

6
4
1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...