在Python语言中,可以在函数中定义函数. 这种在函数中嵌套定义的函数也叫内部函数.我们来看下面的代码:
上述代码中,定义了函数greet,在函数greet内部又定义了一个函数inner_func, 并调用该函数打印了一串字符.
我们可以看到,内部函数inner_func的定义和使用与普通函数基本相同.需要注意的是变量的作用域,在上述代码中,函数参数name对于全局函数greet是局部变量,对内部函数inner_func来说则是非局部变量.内部函数对于非局部变量的访问规则类似于标准的外部函数访问全局变量.
从这个例子我们还可以看到内部函数的一个作用,就是通过定义内部函数的方式将一些功能隐藏起来,防止外部直接调用.常见的场景是,在一个复杂逻辑的函数中,将一些小的任务定义成内部函数,然后由这个外层函数使用,这样可以使代码更为清晰,易于维护.这些内部函数只会在这个外层函数中使用,不能被其他函数或模块使用.
在Python语言中, 函数也是对象,它可以被创建、赋值给变量,或者作为函数的返回值.我们来看下面这个例子.
在上述代码中,在函数gen_greet内部定义了inner_func函数,并返回了一个inner_func函数对象.外部函数gen_greet返回了一个函数对象,所以像gen_greet这样的函数也叫工厂函数.
在内部函数inner_func中,使用了外部函数的传参greet_words(非局部变量),以及函数的参数name(局部变量),来打印一个字符串.
此时此刻呢,调用gen_greet("Hello")创建一个函数对象say_hello,紧接着调用say_hello("Mr. Zhang"),输出的结果为:Hello, Mr. Zhang!
同样的,调用gen_greet("Hi")创建一个函数对象say_hi,调用say_hello("Mr. Zhang"),输出的结果为:Hi,Tony!
我们可以发现,gen_greet返回的函数对象具有记忆功能,它能够把所需使用的非局部变量保存下来,用于后续被调用的时候使用.这种保存了非局部变量的函数对象被称作闭包(closure).
那么闭包是如何实现的呢?其实并不复杂,函数对象中有一个属性__closure__,它就是在创建函数对象时用来保存这些非局部变量的.
__closure__属性是一个元组或者None类型.在上述代码中,我们可以通过下面方式查看:
函数的嵌套所实现的功能大都可以通过定义类的方式来实现,而且类是更加面向对象的代码编写方式.
嵌套函数的一个主要用途是实现函数的装饰器.我们看下面的代码:
通过了解了嵌套函数和闭包的工作原理,我们在使用过程中就能够更加得心应手了.
之前 分析了装饰器的语法,由此可以直接推导出其基本框架.但为了写出一个功能完整的装饰器,还需要了解一个概念——闭包.
闭包(closure) ,是引用了自由变量的函数. 这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外.
看下面的例子
对 f 内部的函数 g 来说,参数 a 既不是它的参数,也不是它的局部变量,而是它的自由变量.该自由变量可以
闭包和嵌套函数的概念有所区别.闭包当然是嵌套函数,但没有引用自由变量的嵌套函数却不是闭包.
Python 的函数有一个只读属性 __closure__ ,存储的就是函数所引用的自由变量,
如果仅仅是嵌套函数,它的 __closure__ 应该是 None .
闭包有个重要的特性:内部函数只能引用而不能修改外部函数中定义的自由变量.试图直接修改只有两种结果,要么运行出错,要么你以为你修改了,实际并没有.
不能修改不是因为 Python 设计者故意限制,不给它权限,而是外部的自由变量被内部的局部变量覆盖了;被覆盖了也不是闭包独有的特性,从普通函数内部同样也不能直接修改全局变量.Python 命名空间的查找规则简写为 LEGB,四个字母分别代表 local、enclosed、global 和 build-in,闭包外层函数的命名空间就是 enclosed.Python 在检索变量时,按照 L - E - G - B 的顺序依次查找,如果在 L 中找到了变量,就不会继续向后查找.
在示例 1 中,你的本意是修改自由变量 number ,然而并不能:由于存在对 number 的赋值语句( number += 1 ),Python 会认为 number 是 printer 的局部变量,可是在局部变量字典中又查找不到它的定义,只好抛出异常.抛出的异常不是因为不能修改自由变量,而是局部变量还没赋值就被引用了.
怎么才能修改呢?
下面的例子很好地展示了自由变量的特点:与引用它的函数一同存在,而想要修改它,得小心谨慎.
在函数中可以定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包.
闭包可以用来在一个函数与一组私有变量之间创建关联关系.
在给定函数被多次调用的过程中,这些私有变量能够保持其持久性.
形成闭包的三个条件
必须有一个内嵌函数—这对应函数之间的嵌套;
内嵌函数必须引用一个定义在闭合范围内的变量—内部函数引用外部变量;
外部函数必须返回内嵌函数—必须返回内部函数.
换句话来说:闭包的概念很简单,一个可以引用在函数闭合范围内变量的函数,即内部函数,只有那个内部函数才有所谓的__closure__属性.
闭包的原理
形成闭包之后,闭包函数会获得一个非空的_Closure_属性,这个属性是一个元组.
组里面的对象为cell对象,而访问cell对象的cell_contents属性则可以得到闭包变量的当前值.
而随着闭包的继续调用,变量会进行再次更新.由此可见,一般形成闭包之后,Python确定会将_closure_和闭包函数绑定作为储存闭包变量的场所.
闭包的好处是什么?
其实,闭包并不是必须的.
没有闭包的话,Python的功能不会受到任何影响;但有了闭包之后,可以提供一种额外的解决方案.
在python中,函数可以被嵌套定义,也就是说,函数中可以定义函数.该函数还可以将其内部定义的函数作为返回值返回.
闭包的定义:一般来说,我们可以认为,如果一个函数可以读取其他函数中的局部变量,那么它们就构成了闭包.
注意 :闭包的定义不是特别清晰,但大体上的意思是这样的.
我们知道,普通的函数是可以使用全局变量的
类似的,函数中定义的函数,也是可以使用外部函数的变量的.所以呢,满足了函数读取了其他函数局部变量的这一条件,他们所以呢构成了闭包.
在闭包的使用中,我们可以先给外部的函数赋予不同的局部变量,然后再调用其中内部的函数时,就可以读取到这些不同的局部变量了.
外部变量的使用 在普通函数中,虽然可以直接使用全局变量,但是不可以直接修改全局变量.从变量的作用域来说,一旦你尝试修改全局变量,那么就会尝试创建并使用一个同名的局部变量.所以呢,如果你需要在普通函数中修改全局变量,需要使用global
同样的,如果你希望通过定义在内部的函数去修改其外部函数的变量,那么必须使用nonlocal
以上就是土嘎嘎小编为大家整理的python函数必报相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!