implementing python generators with closures

£可爱£侵袭症+ 提交于 2019-12-23 02:57:08

问题


how can i get rid of the globals in fib_gen2? I don't want to use native generators or classes per this gist, this is an academic exercise, though I am interested improvements in any of the implementations.

def ftake(fnext, last):
    return [fnext() for _ in xrange(last)]

def fib_gen2():
    global a; a = 1
    global b; b = 1
    def next():
        global a; global b;
        r = a
        a, b = b, a + b
        return r
    return next

assert [1,1,2,3,5] == ftake(fib_gen2(), 5)

回答1:


In Python 3.x, you can use the nonlocal statement:

def fib_gen2():
    a = b = 1
    def next():
        nonlocal a, b
        a, b = b, a + b
        return b - a
    return next

In Python 2.x, you'll need to use some hack:

def fib_gen2():
    ab = [1, 1]
    def next():
        ab[:] = ab[1], ab[0] + ab[1]
        return ab[1] - ab[0]
    return next

This unsatisfactory situation was the very reason for the introduction of nonlocal in Python 3.x.

Python has no variable declarations, so it has to figure out the scope of each variable itself. It does so by a simple rule: If there is an assignment to a name inside a function, this name is local to that function -- except it is explicitly declared global or nonlocal. In the second example, there is no assignment to the name ab -- the list is modified, but the name is not reassigned. Thus the scope is the enclosing function.




回答2:


If I really had to avoid generators, I'd probably do this:

def ftake(fnext, last):
    return [fnext() for _ in xrange(last)]

def fib_gen3():
    def step():
        r = step.a
        step.a, step.b = step.b, step.a + step.b
        return r
    step.a = 1
    step.b = 1
    return step

>>> ftake(fib_gen3(), 10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]



回答3:


This is kind of cheating so hopefully someone can give you a better answer but:

def ftake(fnext, last):
    return [fnext() for _ in xrange(last)]

def fib_gen2():
    fib_gen2.a = 1
    fib_gen2.b = 1
    def next():
        r = fib_gen2.a
        fib_gen2.a, fib_gen2.b = fib_gen2.b, fib_gen2.a + fib_gen2.b
        return r
    return next

assert [1,1,2,3,5] == ftake(fib_gen2(), 5)


来源:https://stackoverflow.com/questions/9355179/implementing-python-generators-with-closures

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!