(点击
上方公众号
,可快速关注)
来源:geekvi
链接:segmentfault.com/a/1190000007510013
在 Python 中,函数也是一个对象。因此,我们在定义函数时,可以再嵌套定义一个函数,并将该嵌套函数返回,比如:
from math import pow
def make_pow
(
n
)
:
def inner_func
(
x
)
:
# 嵌套定义了 inner_func
return
pow
(
x
,
n
)
# 注意这里引用了外部函数的 n
return
inner_func
# 返回 inner_func
上面的代码中,函数 make_pow 里面又定义了一个内部函数 inner_func,然后将该函数返回。因此,我们可以使用 make_pow 来生成另一个函数:
>>>
pow2
=
make_pow
(
2
)
# pow2 是一个函数,参数 2 是一个自由变量
>>>
pow2
function inner_func
at
0x10271faa0
>
>>>
pow2
(
6
)
36.0
我们还注意到,内部函数 inner_func 引用了外部函数 make_pow 的自由变量 n,这也就意味着,当函数 make_pow 的生命周期结束之后,n 这个变量依然会保存在 inner_func 中,它被 inner_func 所引用。
>>>
del
make_pow
# 删除 make_pow
>>>
pow3
=
make_pow
(
3
)
Traceback
(
most recent call
last
)
:
File
"
"
,
line
1
,
in
module
>
NameError
:
name
'make_pow'
is
not
defined
>>>
pow2
(
9
)
# pow2 仍可正常调用,自由变量 2 仍保存在 pow2 中
81.0
像上面这种情况,一个函数返回了一个内部函数,该内部函数引用了外部函数的相关参数和变量,我们把该返回的内部函数称为闭包(Closure)。
在上面的例子中,inner_func 就是一个闭包,它引用了自由变量 n。
闭包的作用
>>>
pow_a
=
make_pow
(
2
)
>>>
pow_b
=
make_pow
(
2
)
>>>
pow_a
==
pow_b
False
这里构造一个类,用于求一个点到另一个点的距离:
from math import sqrt
class
Point
(
object
)
:
def __init__
(
self
,
x
,
y
)
:
self
.
x
,
self
.
y
=
x
,
y
def get_distance
(
self
,
u
,
v
)
:
distance
=
sqrt
((
self
.
x
-
u
)
**
2
+
(
self
.
y
-
v
)
**
2
)
return
distance
>>>
pt
=
Point
(
7
,
2
)
# 创建一个点
>>>
pt
.
get_distance
(
10
,
6
)
# 求到另一个点的距离
5.0
用闭包来实现:
def point
(
x
,
y
)
:
def get_distance
(
u
,
v
)
:
return
sqrt
((
x
-
u
)
**
2
+
(
y
-
v
)
**
2
)
return
get_distance
>>>
pt
=
point
(
7
,
2
)
>>>
pt
(
10
,
6
)
5.0
可以看到,结果是一样的,但使用闭包实现比使用类更加简洁。
常见误区
闭包的概念很简单,但实现起来却容易出现一些误区,比如下面的例子:
def count
()
:
funcs
=
[]
for
i
in
[
1
,
2
,
3
]
:
def
f
()
:
return
i
funcs
.
append
(
f
)
return
funcs
在该例子中,我们在每次 for 循环中创建了一个函数,并将它存到 funcs 中。现在,调用上面的函数,你可能认为返回结果是 1, 2, 3,事实上却不是:
>>>
f1