浅谈python闭包

1.何为闭包javascript

在百度百科里面,看到了这样的定义:java

闭包就是可以读取其余函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,因此闭包能够理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部链接起来的桥梁。闭包

闭包包含自由(未绑定到特定对象)变量,这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。“闭包” 一词来源于如下二者的结合:要执行的代码块(因为自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(做用域)。函数

从上面两段话咱们能够更好的理解:在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,而且外函数的返回值是内函数的引用。这样就构成了一个闭包。spa

下面是一个闭包的小例子:code

def outer():
    a = 6
    def inner():
        b = 8
        print(a)
        print(b)
    return inner

if __name__ == '__main__':
    res = outer()
    res()

执行结果:

>>>6
>>>8

咱们能够看到,当调用外部函数outer()时,会返回一个内部函数的引用res,再经过res()执行了内部函数,返回打印结果6和8orm

这上面的例子中,a做为外部函数outer()的局部变量,其被分配的内存在外部函数执行后应被释放,但在外部函数执行后,发现本身的局部变量将被内部函数引用,就把这个变量绑定给了内部函数,而后再本身结束。此处的outer()的局部变量a称之为自由变量,所以,对于内部函数inner()而言,其自由变量和局部变量咱们能够经过下面的命令获得:对象

>>> res.__code__.co_freevars
('a',)
>>> res.__code__.co_varnames
('b',)

上面咱们说到,外部函数的局部变量a被绑定到了内部函数,咱们能够经过返回函数res的__closure__属性找到它blog

>>> res.__closure__[0].cell_contents
6

 

2.闭包的变量ip

def outer():
    a = 6
    def inner():
        b = 8
        a += 1
        print(a)
        print(b)
    return inner

if __name__ == '__main__':
    res = outer()
    res()

执行函数会报错:UnboundLocalError: local variable 'a' referenced before assignment

这个报错的意思是内部函数引用的变量a在赋值前已经被引用,缘由在于变量a是数字,不可变类型,a += 1至关于在内部函数中建立了局部变量a = a + 1,这样a再也不是自由变量,也不存在闭包。

这里咱们能够尝试下外部函数的局部变量为可变类型的状况:

def outer():
    a = [1,2,3]
    def inner():
        b = 8
        a = [4,5]
        print(a)
        print(b)
    return inner

if __name__ == '__main__':
    res = outer()
    res()

执行结果:
[4, 5]
8

能够看到,当a为可变类型时,函数能够正确执行。那么当a为不可变类型但又想在内部函数中改变a的值该怎么作,答案是利用nonlocal关键字。

def outer():
    a = 6
    def inner():
        nonlocal a
        b = 8
        a += 1
        print(a)
        print(b)
    return inner

if __name__ == '__main__':
    res = outer()
    res()

执行结果:
7
8

 

3.闭包的应用

下面模拟一个nba球员信息的小例子

首先用普通函数实现:

class PlayerInfo():
    def __init__(self, name):
        self.name = name
    def position(self, position):
        return "{} is {}".format(self.name, position)

curry = PlayerInfo("Stephen Curry")
print(curry.position("PG"))
lbj = PlayerInfo("Lebron James")
print(lbj.position("SF"))

执行后:

Stephen Curry is PG
Lebron James is SF

下面用闭包函数来实现

def get_name(name):
    def get_position(position):
        return "{} is {}".format(name,position)
    return get_position

if __name__ == "__main__":
    player01 = get_name("Stephen Curry")
    print(player01("PG"))
    player02 = get_name("Lebron James")
    print(player02("SF"))

所以咱们能够看出,对于实现少许方法的类,咱们能够用闭包代替。

相关文章
相关标签/搜索