闭包就是函数和它的环境(变量)
1. 尽量把 closure 中的变量变成 local 变量
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()
用文中的例子来解释:
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")
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
错误代码
>>> 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
闭包可以看成是函数的函数,当我们有一个函数需要多个变量时,闭报可以帮我们先确定一个变量,然后返回只还有剩下变量的函数.
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)