Python---闭包

一般,在使用了嵌套函数时才会出现闭包。其实,闭包是指延伸了作用域的函数,这个闭包的函数中引用了不在本函数体中定义的非全局变量,即出现了自由变量
看一个简单的例子:

>>> def make_averager():
    series = []
    def averager(new_val):
        series.append(new_val)
        total = sum(series)
        return total/len(series)
    return averager

>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(12)
11.0
>>> avg(11)
11.0

avg这个函数可以用来计算新添加的值与之前所有值的均值。
我们来看看make_averager这个函数,这个函数内部定义了一个函数averager,并将内部函数返回。
对avgerager进行审查:

>>> avg.__code__.co_varnames
('new_val', 'total')
>>> avg.__code__.co_freevars
('series',)

可以看到,列表series并不是avg的变量,series对于avg来说是一个自由变量(free variable),即未在本地作用域中绑定的变量。

使用关键字 nonlocal 可以显示的声明自由变量,改写上述的函数:

>>> def make_averager():
    count = 0
    total = 0
    def averager(new_val):
        count += 1
        total += new_val
        return total/count
    return averager

>>> avg = make_averager()
>>> avg(10)
Traceback (most recent call last):
  File "<pyshell#118>", line 1, in <module>
    avg(10)
  File "<pyshell#116>", line 5, in averager
    count += 1
UnboundLocalError: local variable 'count' referenced before assignment

奇怪,为什么会出现错误呢?
count += 1 语句的作用与 count = count + 1 一样,因此,在averager的定义体中为count赋值了,其实会隐式地创建局部变量count ,total也会出现同样的问题。
为了解决这个问题,Python3引入了nonlocal 声明,作用是把变量标记为自由变量,上述的例子可改为:

>>> def make_averager():
    count = 0
    total = 0
    def averager(new_val):
        nonlocal count,total
        count += 1
        total += new_val
        return total/count
    return averager

>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0

猜你喜欢

转载自blog.csdn.net/Miha_Singh/article/details/81184542