首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

python函数作用域与闭包

函数的定义

在python中,是用def来创建一个函数,实际上def只是完成了一个类似与赋值的操作---------把一个函数对象赋值给一个变量名,还记得我们之前说过在python中变量名只是一个标识符,相当于起到了一个指针的作用,它没有类型(明确这一点是很重要的),又因为python中的一切皆对象,函数当然也不例外,所以,函数被创建后就可以赋值给任意的变量名,也可以作为参数传递给另外一个函数,也可以作为函数的返回值。下面是相应的代码演示

函数赋值给任意变量名:

这里写图片描述

函数作为参数传递:

这里写图片描述

函数对象作为返回值:

这里写图片描述函数作用域

python中有三种(或四种)域作用域相关的作用域。本地变量、(外层函数的本地变量)、全局变量、内建变量

本地变量就是在一个函数内部的变量,全局变量就是不在特定的函数内的,内建变量比较特殊,它是python在开发时就被设计好的一些变量,我们可以通过builtins模块查看。

这里写图片描述

可以看到,其实这些内建的变量就是写进了builtins这个文件里而已,但是这个文件里没有写builtins,所以我们需要导入builtins模块,才能查看它。

这里还有一个奇怪的变量,我把它单独拿出来说--------------外层函数的本地变量,它是伴随着函数嵌套出现的。我们举一个例子来说明:

上面的x就是所谓的外层函数的本地变量,当然它是相对于内层函数fun而言的,它也是本地变量(test的),但是它所处的作用域又不同于fun中的作用域,所以,如果现在fun中再创建一个x变量,他们是不冲突的。

LEGB规则

谈完了函数的作用域,我们就来谈一谈python中变量名的解析规则。对于一个def语句:

变量名分为三个作用域查找:首先是本地(L),之后是函数内(E)(如果有的话),之后是全局(G),最后是内置(B)

在默认情况下,变量名赋值会创建或改变本地变量

LEGB图示:

这里写图片描述

因为变量名赋值会创建本地变量,所以我们在函数内部想要改变全局变量的值的时候就不能直接给它赋值了(不考虑全局变量作为参数传递进函数),必须要用到global语句来声明这是一个全局变量:

global用于声明一个变量是全局变量。但是有一点小细节需要注意,当全局变量是一个可变对象时,例如一个列表,我们可以直接在函数内部对它进行修改,而不是赋值

这里时对可变对象在原处的修改,而不是赋值!!

闭包

首先还得从基本概念说起,什么是闭包呢?来看下维基上的解释:

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

上面提到了两个关键的地方: 自由变量 和 函数, 这两个关键稍后再说。还是得在赘述下“闭包”的意思,望文知意,可以形象的把它理解为一个封闭的包裹,这个包裹就是一个函数,当然还有函数内部对应的逻辑,包裹里面的东西就是自由变量,自由变量可以在随着包裹到处游荡。当然还得有个前提,这个包裹是被创建出来的。

在通过Python的语言介绍一下,一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包。你在调用函数A的时候传递的参数就是自由变量。

举个栗子:

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

另外再说一点,闭包并不是Python中特有的概念,所有把函数做为一等公民的语言均有闭包的概念。不过像Java这样以class为一等公民的语言中也可以使用闭包,只是它得用类或接口来实现。

闭包与装饰器

其实装饰器就是闭包的一种应用,下面来引用廖老师教程中的一个例子:

上面的log函数就是一个装饰器。它接受一个函数参数,我们使用python的@语法,把装饰器放在函数的定义处,这样当执行now函数的时候,就会自动执行log函数。

以上程序的输出结果为:

闭包的作用

闭包的最大特点是可以将父函数的变量与内部函数绑定,并返回绑定变量后的函数(也即闭包),此时即便生成闭包的环境(父函数)已经释放,闭包仍然存在,这个过程很像类(父函数)生成实例(闭包),不同的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时创建,一般程序执行完毕后作用域才释放,因此对一些需要重用的功能且不足以定义为类的行为,使用闭包会比使用类占用更少的资源,且更轻巧灵活。

关注web安全

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180615G1JW3W00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券