python闭包函数 python3 闭包( 五 )


# 每次循环,这里都会重新生成一个函数 , 然后把重新生成的函数赋值给 locals['f']
def f():
return i * i# 引用了'i'这个名字,但并不是引用了'i'对应的值
# 等价于 locals['fs'].append(locals['f'])
# f 不是函数,它只是一个名字'f' 。f 引用的东西,也就是locals['f']才是真正的函数
fs.append(f)
# 于是这个for循环生成了三个函数,这三个函数是没有名字的,这个函数运行完后 , 它们跟'f'这个名字就毛关系都没有了(是的我说慌了,但可以先不管)
# 把整个列表返回,这个列表包含了三个函数
return fs
# count()返回三个函数的列表,unpack 列表的语法把列表中的三个函数抽出来 , 重新给他们命名为 f1, f2, f3
# 也就是说 , 
# locals['f1'] = 列表中的第1个函数
# locals['f2'] = 列表中的第2个函数
# locals['f3'] = 列表中的第3个函数
# 这三个函数跟'f'这个名字现在毛关系都没有 。(其实是有的,但为了说明需要简化,现在你可以完全不管括号里面说的话)
f1, f2, f3 = count()
print f1(), f2(), f3()
# 好了我们运行它们,输入都是 9
# def f():
#return i * i
这是因为 f1 现在对应的函数,里面引用了 'i' 这个字符串,我们根据 'i '这个字符串去找它对应的值,先找到 f 当前的locals字典,发现没有,因为函数定义的时候没有定义 i 变量 。然后再去closure['i']里面找 , 因为Python是通过closure字典实现闭包的(就当它是对的好不好),所以我们可以在closure['i']找到值,这个值就是我们上一次运行的时候count函数里面残留的locals['i'],而由于for循环三遍之后 , locals['i'] == 3,所以找到 i 的值就是3 。所以最后输出都是9
Python嵌套函数和闭包在Python语言中,可以在函数中定义函数 。这种在函数中嵌套定义的函数也叫内部函数 。我们来看下面的代码:
上述代码中,定义了函数greet,在函数greet内部又定义了一个函数inner_func, 并调用该函数打印了一串字符 。
我们可以看到,内部函数inner_func的定义和使用与普通函数基本相同 。需要注意的是变量的作用域 , 在上述代码中,函数参数name对于全局函数greet是局部变量,对内部函数inner_func来说则是非局部变量 。内部函数对于非局部变量的访问规则类似于标准的外部函数访问全局变量 。
从这个例子我们还可以看到内部函数的一个作用 , 就是通过定义内部函数的方式将一些功能隐藏起来,防止外部直接调用 。常见的场景是,在一个复杂逻辑的函数中,将一些小的任务定义成内部函数,然后由这个外层函数使用 , 这样可以使代码更为清晰 , 易于维护 。这些内部函数只会在这个外层函数中使用,不能被其他函数或模块使用 。
在Python语言中, 函数也是对象,它可以被创建、赋值给变量,或者作为函数的返回值 。我们来看下面这个例子 。
在上述代码中,在函数gen_greet内部定义了inner_func函数 , 并返回了一个inner_func函数对象 。外部函数gen_greet返回了一个函数对象,所以像gen_greet这样的函数也叫工厂函数 。
在内部函数inner_func中,使用了外部函数的传参greet_words(非局部变量),以及函数的参数name(局部变量),来打印一个字符串 。
接下来,调用gen_greet("Hello")创建一个函数对象say_hello,紧接着调用say_hello("Mr. Zhang"),输出的结果为:Hello, Mr. Zhang!
同样的,调用gen_greet("Hi")创建一个函数对象say_hi,调用say_hello("Mr. Zhang"),输出的结果为:Hi,Tony!

推荐阅读