最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

Python进阶:携带状态的闭包

来源:动视网 责编:小采 时间:2020-11-27 14:26:51
文档

Python进阶:携带状态的闭包

Python进阶:携带状态的闭包:闭包在 Python 中,函数也是一个对象。因此,我们在定义函数时,可以再嵌套定义一个函数,并将该嵌套函数返回,比如:from math import pow def make_pow(n): def inner_func(x): # 嵌套定义了 inner_func return pow(x, n) #
推荐度:
导读Python进阶:携带状态的闭包:闭包在 Python 中,函数也是一个对象。因此,我们在定义函数时,可以再嵌套定义一个函数,并将该嵌套函数返回,比如:from math import pow def make_pow(n): def inner_func(x): # 嵌套定义了 inner_func return pow(x, n) #


闭包

在 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 "<stdin>", 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, f2, f3 = count()
    >> > f1()
    3
    >> > f2()
    3
    >> > f3()
    3

    为什么呢?原因在于上面的函数 f 引用了变量 i ,但函数 f 并非立刻执行,当 for 循环结束时,此时变量 i 的值是3, funcs 里面的函数引用的变量都是 3,最终结果也就全为 3。

    因此,我们应尽量避免在闭包中引用循环变量,或者后续会发生变化的变量。

    那上面这种情况应该怎么解决呢?我们可以再创建一个函数,并将循环变量的值传给该函数,如下:

    def count():
     funcs = []
     for i in [1, 2, 3]:
     def g(param):
     f = lambda: param # 这里创建了一个匿名函数
     return f
     funcs.append(g(i)) # 将循环变量的值传给 g
     return funcs
    >> > f1, f2, f3 = count()
    >> > f1()
    1
    >> > f2()
    2
    >> > f3()
    3

    小结

  • 闭包是携带自由变量的函数,即使创建闭包的外部函数的生命周期结束了,闭包所引用的自由变量仍会存在。

  • 闭包在运行可以有多个实例。

  • 尽量不要在闭包中引用循环变量,或者后续会发生变化的变量。

  • 文档

    Python进阶:携带状态的闭包

    Python进阶:携带状态的闭包:闭包在 Python 中,函数也是一个对象。因此,我们在定义函数时,可以再嵌套定义一个函数,并将该嵌套函数返回,比如:from math import pow def make_pow(n): def inner_func(x): # 嵌套定义了 inner_func return pow(x, n) #
    推荐度:
    标签: 状态 携带 python
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top