嵌套函数与非局部变量
在函数中定义另一个函数称为嵌套函数。嵌套函数可以访问包围范围内的变量。
def print_msg(msg): def printer(): print(msg) printer() print_msg("Hello") #Hello
nonlocal关键字
使用nonlocal关键字可以修改外层函数中变量的值:
def outer(): a = 1
def inner(): a += 1
print("Inner", a) inner() print("Outer", a) outer() #UnboundLocalError: local variable 'a' referenced before assignment
def outer(): a = 1
def inner(): nonlocal a a += 1
print("Inner", a) inner() print("Outer", a) outer()
输出:
Inner 2 Outer 2
闭包
闭包也称词法闭包,如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure),这里说的作用域就是nonlocal;通俗来讲,闭包就是把一个函数(方法)作为一个变量来使用。
在Python中创建闭包必须满足的标准将在以下几点:
- 必须有一个嵌套函数(函数内部的函数)。
- 嵌套函数必须引用封闭函数中定义的值。
- 闭包函数必须返回嵌套函数。
利用闭包实现一个计数器:
def counter(): i = 0 def nested(): nonlocal i i += 1
return i return nested c = counter() print(c(),c(),c(),end=" ") #1 2 3
返回的函数并没有立刻执行,而是直到调用了c()才执行。
返回的函数中不要引用循环变量:
def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs f1, f2, f3 = count() print(f1()) #9
print(f2()) #9
print(f3()) #9
全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。
如果一定要使用循环变量,解决方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
def count(): def f(j): def g(): return j*j return g fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs f1, f2, f3 = count() print(f1()) #1
print(f2()) #4
print(f3()) #9