这一次彻底搞清楚闭包函数

闭包(closure)是函数式编程的重要的语法结构。
函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。
在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。
函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。
闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

不同的语言实现闭包的方式不同。
python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到python使用对象来实现一些特殊的语法)。
python一切皆对象,函数这一语法结构也是一个对象
在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。

一、闭包函数的概念

在搞清楚一个事物的原理,必须先知道相关的概念和定义,关于闭包函数的概念,我从维基百科上找了段相关的定义

在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

维基百科这段话说的云里雾里的,看完后有点让人思考人生的感觉。对于闭包的概念我想用一句话解释清楚
闭包函数其实是定义在内部函数并且包含对外部作用域而非全局作用域的代码引用
还是很难理解,还是来一段代码看看吧

def mybook():
  book = "this is my book"
  def innerfunc():
    print(book)   # 闭包
  innerfunc()
mybook()

这里面调用mybook的时候就产生了一个闭包——innerfunc,并且该闭包持有自由变量——book,因此这也意味着,当函数mybook的生期结束之后,book这个变量依然存在,因为它被闭包引用,所以不会被内存回收。

闭包并不是Python中特有的概念,所有编程语言的函数均有闭包的概念。
在为学习闭包之前,我们都是通过参数将外部的值传给函数,而闭包提供了另外一种思路,包起来,嗯真的很不错哦。

二、为什么使用闭包

通过第一部分介绍,不知道你有没有感觉这个东西和类有点相似,相似点在于他们都提供了对数据的封装。不同的是闭包本身就是个方法。和类一样,我们在编程时经常会把通用的东西抽象成类,以复用代码通用的功能。闭包也是一样,当我们需要函数粒度的抽象时,闭包就是一个很好的选择。

我们在外界可以访问内部函数. 那这个时候内部函数访问外部就不⼀定。
因为在外部, 我可以选择在任意的时间去访问内部函数。
如果⼀个函数执⾏完毕. 则这个函数中的变量以及局部命名空间中的内容都将会被销毁。
在闭包中,如果变量被销毁了那内部函数将不能正常执⾏。
所以,python规定如果你在内部函数中访问了外层函数中的变量,那么这个变量将不会消亡,将会常驻在内存中。
也就是说使⽤闭包, 可以保证外层函数中的变量在内存中常驻,提供后面的函数使用。
也就是说:
返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

三、闭包的应用场景

在python中很重要也很常见的一个使用场景就是装饰器,Python为装饰器提供了一个很友好的"语法糖",让我们可以很方便的使用装饰器。
在装饰器的这个例子中,闭包(wrapper)持有了外部的func这个参数,并且能够接受外部传过来的参数,接受过来的参数在原封不动的传给func,并返回执行结果。

3.1 装饰器

def decorator_func(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper
 
@decorator_func
def func(name):
    print 'my name is', name

# 等价于
#decorator_func(func)

rest = func('Coco')
print(rest)

3.2 惰性求值

第二个场景 ,就是基于闭包的一个特性——“惰性求值”。这个应用非常常见,比如目前应用非常多的爬虫的案例。

import requests
def html():
    content = requests.get("http://www.baidu.com").read()
    def get_content():
        return content
    return get_content
all = html() 
# 后⾯需要⽤到这⾥⾯的内容就不需要在执⾏⾮常耗时的⽹络连接操作了
content = all() # 获取内容
print(content)
content2 = all() # 重新获取内容
print(content2)

参考链接:http://python.jobbole.com/83969/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值