Python Closure 闭包

来源:互联网 发布:数据库管理员要求 编辑:程序博客网 时间:2024/06/08 05:55

  • Summary
  • globals locals
  • 闭包
  • 闭包需要注意的地方
    • 1 不能在闭包中引用任何会改变的变量
    • 2
  • 闭包的应用
    • 1 为英语增加复数形式的代码

Summary

闭包就是函数和它的环境(变量)
1. 尽量把 closure 中的变量变成 local 变量


1. globals, locals

Citation

先来说下作用域,一共有三种作用域
– local namespace: 作用范围为当前函数或者类方法
– global namespace: 作用范围为当前模块
– build-in namespace: 作用范围为所有模块

python 也是按照 local -> global -> build-in 的顺序来查找的.
python 中的 locals() 和 globals() 可以分别查到他们中的变量

s = "string in global"num = 99def numFunc(a, b):    num = 100    print "print s in numFunc: ", s    def addFunc(a, b):        s = "string in addFunc"        print "print s in addFunc: ", s        print "print num in addFunc: ", num        print "locals of addFunc: ", locals()        print         return "%d + %d = %d" %(a, b, a + b)    print "locals of numFunc: ", locals()    print     return addFunc(a, b)numFunc(3, 6)    print "globals: ", globals()

2. 闭包

用文中的例子来解释:

def greeting_conf(prefix):    def greeting(name):        print prefix, name    return greetingmGreeting = greeting_conf("Good Morning")mGreeting("Wilber")mGreeting("Will")printaGreeting = greeting_conf("Good Afternoon")    aGreeting("Wilber")aGreeting("Will")

即使我们 delete 了greeting_conf 函数, mGreeting 函数仍然记得住 prefix 变量. 它不是 local 函数,但它存在了函数的 __closure__中。

实际上,这样的代码在 python 中可以写成

@greeting_confdef greeting_conf(prefix):    def greeting(name):        print prefix, name    return greetingmGreeting("Wilber")mGreeting("Will")

3. 闭包需要注意的地方

3.1 不能在闭包中引用任何会改变的变量

def ret_func():    arr = []    for i in range(3):        arr.append(lambda: i*i)    return arrresults = ret_func()func1, func2, func3 = results[0], results[1], results[2]>>> func1()4>>> func2()4>>> func3()4

变量 i 是保存在函数的 __closure__中,这个变量是在函数调用时才被绑定的,所以等三个函数调用时,i 都是 2 了。 但是 local 变量的值不会变, 所以这里把 i 当成 local 变量传入就可以了

def ret_func():    arr = []    for i in range(3):        arr.append(lambda i=i: i*i)    return arr

3.2

错误代码

>>> def foo():         a = 1         def bar():                a = a +1                return a         return bar()  >>> foo()  Traceback (most recent call last):    File "<pyshell#73>", line 1, in <module>      foo()    File "<pyshell#72>", line 6, in foo      return bar()    File "<pyshell#72>", line 4, in bar      a = a +1  UnboundLocalError: local variable 'a' referenced before assignment  

对于 a=a+1, python先检查左边的值,认为 a 是一个局部变量,然后再看右边的计算,但是又在局部变量中找不到 a, 所以抛处异常。

正确的当时是把指改成 list 即可。

正确代码

>>> def foo():         a = [1]         def bar():                a[0] = a[0] + 1                return a[0]         return bar()  >>> foo()2  

4. 闭包的应用

闭包可以看成是函数的函数,当我们有一个函数需要多个变量时,闭报可以帮我们先确定一个变量,然后返回只还有剩下变量的函数.

4.1 为英语增加复数形式的代码

Citation

import re def build_match_and_apply_functions(pattern, search, replace):     def matches_rule(word):        return re.search(pattern, word)     def apply_rule(word):        return re.sub(search, replace, word)     return (matches_rule, apply_rule) # 返回动态函数组成的元组patterns = \    (    ('[sxz]$', '$', 'es'),     ('[^aeioudgkprt]h$', '$', 'es'),     ('(qu|[^aeiou])y$', 'y$', 'ies'),     ('$', '$', 's') )rules = [build_match_and_apply_functions(pattern, search, replace)        for (pattern, search, replace) in patterns]def plural(noun):     for matches_rule, apply_rule in rules:         if matches_rule(noun):             return apply_rule(noun)
0 0