вызов урожая для генератора в другой функции

предположите, что у меня есть некоторый объект менеджера. API этого объекта имеет a main_hook функция, которая получает другую функцию f поскольку это - аргумент и выполняет данный f в цикле, делая некоторый материал, промежуточный каждое повторение:

def main_hook(self,f):
    while (self.shouldContinue()):
        #do some preparations
        f(self)
        #do some tear down

Теперь, я также имею (более точно, хотел бы иметь), функция stop_and_do_stuff, это когда-то названное, остановки main_hook мертвый в он - дорожки, возвращает управление какой бы ни названный func main_hook, и после этого func, законченные, что это выполнение, верните управление к main_hook и продолжите. В основном результат совпадет с выполнением

def main_hook(self,f):
    while (self.shouldContinue()):
        #do some preparations
        yield
        #do some tear down

За исключением того, что вместо этого yield Я хочу иметь вызов к f(), при предоставлении f опция звонить self.stop_and_do_stuff()

Я не могу работать вокруг этого путем создания f также генератор по 2 причинам:

1.f не часть моего API - это дано мне пользователем, который использует мой lib

2. Даже если мог попросить, чтобы он использовал урожай, место в коде, в который он должен будет звонить stop_and_do_stuff не будет непосредственно внутри f, скорее в некотором месте в функциональном стеке, который будет внутри f(), но не непосредственно в нем, например,

def h(manager):
    #do stuff
    if should stop:
        manager.stop_and_do_stuff()
    #do more stuff
def g(manager):
    #some stuff
    if should stop:
        manager.stop_and_do_stuff()
    #more stuff
    if should stop again:
        manager.stop_and_do_stuff()  
    if should call h:
        h()
def f(manager):
    g(manager)

таким образом, если я принимаю решение сделать f генератор, я также должен сделать g генератор и также h, иначе этот прием не будет работать.

Там какое-либо решение ко всему этому? возможно, я пытаюсь решить его неправильный путь?

(Я знаю, что этот вопрос долог и ужасен - лучше, чтобы я мог сделать. Если что-то не ясно, скажите мне, и я разъясню его),

Править

Возможно, бодрость духа 342 является решением?

9
задан olamundo 19 June 2010 в 07:59
поделиться

4 ответа

Я считаю, что мне следует добавить ответ с другой точки зрения, т.е. не пытаясь объяснить, как вы могли бы достичь того, что мы можем понять из того, что вы пытаетесь сделать, но почему yield определенно не может работать.

Когда функция содержит ключевое слово yield , она глубоко модифицируется. Это по-прежнему вызываемая, но уже не обычная функция: она становится фабрикой, возвращающей итератор.

С точки зрения вызывающей стороны нет никакой разницы между тремя приведенными ниже реализациями (за исключением того, что вариант yield намного проще).

##########################################
print "Function iterator using yield",

def gen():
    for x in range(0, 10):
        yield x

f = gen()
try:
    while True:
        print f.next(),
except StopIteration:
    pass

for x in gen():
    print x,

print

#########################################
print "Class iterator defining iter and next",

class gen2(object):

    def __init__(self):
        self.index = 0;
        self.limit = 10;

    def __iter__(self):
        return self

    def next(self):
        if self.index >= self.limit:
            raise StopIteration
        self.index += 1;
        return self.index - 1;


f = gen2()
try:
    while True:
        print f.next(),
except StopIteration:
    pass

for x in gen2():
    print x,
print

#########################################
print "Function iterator using iter() and sentinel",
def gen3():
    def g3():
        if g3.index is None:
            g3.index = 0
        g3.index += 1;
        return g3.index - 1

    g3.index = None
    return iter(g3, 10)

f = gen3()
try:
    while True:
        print f.next(),
except StopIteration:
    pass

for x in gen3():
    print x,
print

Тогда вы должны понимать, что yield - это не столько поток управления, сколько сохранение контекста вызова внутри переменных. Как только это будет понято, вы должны решить, действительно ли API main_loop хочет предоставить итератор вызывающей стороне. Тогда, если это так, если f может зацикливаться, он также должен быть итератором (и должен быть цикл вокруг вызовов f (), как показано ниже).

def main_hook(self,f):
    while (self.shouldContinue()):
        #do some preparations
        for v in f(self):
            yield v
        #do some tear down

Но вам все равно, должна ли f () вызывать внутренние функции g () и т. Д. Это совершенно неважно. Вы предоставляете библиотеку, и ваша проблема пользователя - вызвать ее с соответствующей итерацией. Если вы считаете, что ваш пользователь библиотеки не сможет этого сделать, вам придется изменить общий дизайн.

Надеюсь, это поможет.

2
ответ дан 4 December 2019 в 23:38
поделиться

Я не совсем понимаю, чего именно вы пытаетесь добиться, поэтому, возможно, если вы сможете объяснить проблему подробнее, а не дать решение, это будет лучше.

Из моего частичного понимания, почему бы вам не сделать что-то вроде этого

def main_hook(self,f):
    while (self.shouldContinue()):
        #do some preparations
        stop_and_do_stuff = f(self)
        if stop_and_do_stuff :
            yield

        #do some tear down

Итак, в основном f возвращает флаг для остановки или нет, и если он говорит stop, мы уступаем функции, которая вызвала main_hook, и эта функция может продолжить после выполнения некоторых вещей

например,

class A(object):
    def main_hook(self,f):
        while (self.shouldContinue()):
            #do some preparations
            stop = f(self)
            if stop:
                yield

            #do some tear down

    def shouldContinue(self):
        return True

def f(a):
    return True

a = A()
for x in a.main_hook(f):
    print x
0
ответ дан 4 December 2019 в 23:38
поделиться

Я тоже не все понимаю (как выглядит вызывающий main_hook?), но я бы сказал, что нужно бросать исключение StopNow, когда нужно остановиться, так же как нужно бросать StopIteration, когда генератор закончил работу.

вот как я понял эту штуку, а также то, что я бы сделал.

class StopNow(Exception):
    pass

def main_hook(self,f):
    got_stop_now_exc = False
    while (!got_stop_now_exc and self.shouldContinue()):
        #do some preparations
        try:
             f(self)
        except StopNow:
             got_stop_now_exc = True

        #do some compulsary tear down, exception or not

def stop_and_do_stuff()
    raise StopNow()
def my_f():
    if needed:
        stop_and_do_stuff()

def the_main_hook_caller():
    while i_should:
        managerthingie.main_hook(my_f)
        do_stuff()
1
ответ дан 4 December 2019 в 23:38
поделиться

Описываемое вами поведение выглядит в точности как простой вызов функции. Как показано ниже.

def f(manager):
    print("Entering f")
    manager.stop_and_do_stuff()
    print("Exiting f")

class Manager(Object):
    def shouldContinue(self):
        return True

    def stop_and_do_stuff(self):
        print("Manager stop and do stuff")

    def main_hook(self,f):
        while self.shouldContinue()
            print("Manager Setup")
            f(self)
            print("Manager Tear Down")

Нет проблем, если f () предоставлен другим пользователем или если stop_and_do_stuff вызывается из некоторой внутренней функции. Если вы также хотите, чтобы менеджер мог раскручивать стек из stop_and_do_stuff и действительно выходить в некоторых случаях, не проблема. Просто вызовите какое-то исключение из него, и вы поймаете его из main_hook или верхнего кода.

Вы должны иметь возможность делать изнутри stop_and_and_do_stuff () все, что вы хотите, от вызывающей основной ловушки. Если нет, вы должны объяснить, почему.

Что неясно в вопросе, так это то, что происходит на вызывающей стороне main_hook () и почему вы хотели бы иметь возможность выйти из цикла main_hook, но не совсем. Либо вызывающий main_loop ожидает генератор, либо нет. Вам нужно объяснить эту часть, если вы хотите получить разумный ответ (некоторая контекстная информация также будет полезна, если вы действительно объясните WTF, который вы пытаетесь сделать, и ваши реальные ограничения - вы сказали, что f предоставляется другим пользователем и main_hook есть в библиотеке, что из вызывающего main_hook? - наверное, есть хорошо известные обычные решения).

0
ответ дан 4 December 2019 в 23:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: