Python Closure 闭包

  • 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 = 99

def 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 greeting

mGreeting = greeting_conf("Good Morning")
mGreeting("Wilber")
mGreeting("Will")

print

aGreeting = greeting_conf("Good Afternoon")    
aGreeting("Wilber")
aGreeting("Will")

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

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

@greeting_conf
def greeting_conf(prefix):
    def greeting(name):
        print prefix, name
    return greeting

mGreeting("Wilber")
mGreeting("Will")

3. 闭包需要注意的地方

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

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

results = 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)

你可能感兴趣的:(Python Closure 闭包)