专栏名称: Python开发者
人生苦短,我用 Python。伯乐在线旗下账号「Python开发者」分享 Python 相关的技术文章、工具资源、精选课程、热点资讯等。
目录
相关文章推荐
Python中文社区  ·  超爆回报2682%!轻松复制这个简单暴利的量 ... ·  昨天  
Python爱好者社区  ·  模仿一下领导说话的样子 ·  15 小时前  
Python爱好者社区  ·  今年程序员这薪资是认真的吗? ·  昨天  
python自留地  ·  Python语法基本单词 ·  昨天  
Python中文社区  ·  马斯克一条推特,股价狂飙?AI量化模型揭秘背 ... ·  4 天前  
51好读  ›  专栏  ›  Python开发者

Python : 携带状态的闭包

Python开发者  · 公众号  · Python  · 2016-11-26 22:01

正文

(点击 上方公众号 ,可快速关注)


来源: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







请到「今天看啥」查看全文