invoking yield for a generator in another function

后端 未结 5 2424
灰色年华
灰色年华 2021-02-14 16:06

suppose I have some manager object. This object\'s API has a main_hook function, that gets another function f as it\'s argument, and runs the given

5条回答
  •  失恋的感觉
    2021-02-14 16:15

    I believe I should also add an answer from the other point of view, ie not trying to explain how you could achieve what we can understand of what you are trying to do, but why yield definitely couldn't possibly work.

    When a function contains yield keyword it is deeply modified. It is still a callable but not a normal function any more : it becomes a factory that return an iterator.

    From the caller's point of view there is no difference between the three implementations below (except that the yield one is so much simpler).

    ##########################################
    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
    

    Then you should understand that yield is not much about control flow, but about keeping call context inside variables. Once it is understood you have to decide if the API of main_loop really want to provide an iterator to it's caller. Then if so, if f may loop it must should also be an iterator (and there should be a loop around calls to f() like below).

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

    But you should not care if f() has to call inner functions g(), etc. That is completely irrelevant. You provide a lib and it is your user problem to call with an appropriate iterable. If you believe your lib user won't be able to, you will have to change the overall design.

    Hope it helps.

提交回复
热议问题