用闭包实现python生成器

Dus*_*etz 1 python lambda closures

我如何摆脱fib_gen2中的全局变量?我不想按照这个要点使用本机生成器或类,这是一个学术练习,尽管我对任何实现都有兴趣改进.

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)
Run Code Online (Sandbox Code Playgroud)

Sve*_*ach 9

在Python 3.x中,您可以使用以下nonlocal语句:

def fib_gen2():
    a = b = 1
    def next():
        nonlocal a, b
        a, b = b, a + b
        return b - a
    return next
Run Code Online (Sandbox Code Playgroud)

在Python 2.x中,您需要使用一些hack:

def fib_gen2():
    ab = [1, 1]
    def next():
        ab[:] = ab[1], ab[0] + ab[1]
        return ab[1] - ab[0]
    return next
Run Code Online (Sandbox Code Playgroud)

这种令人不满意的情况是nonlocal在Python 3.x中引入的原因.

Python没有变量声明,因此必须弄清楚每个变量本身的范围.它通过一个简单的规则:如果有一个分配给一个函数内部的名称,这个名称是局部的功能-除了它是显式声明的globalnonlocal.在第二个示例中,没有对名称的赋值ab- 列表已修改,但名称未重新分配.因此范围是封闭功能.