嵌套函数:

python允许创建嵌套函数。也就是说我们可以在函数里面定义函数,而且现有的作用域和变量生存周期依旧不变。

例子:

#encoding=utf-8

def outer():
    name="python"

def inner():#outer函数内部定义的函数
        print name
    return inner()#返回该内部函数

outer()

结果:

理解:

在inner函数中,python解析器需要找一个叫name的本地变量,查找失败后会继续在上层的作用域里面寻找,这个上层作用域定义在outer函数里,python函数可以访问封闭作用域。

对于outer函数中最后一句,返回inner函数调用的结果,需要知道非常重要一点就是,inner也仅仅是一个遵循python变量解析规则的变量名,python解释器会优先在outer的作用域里面对变量名inner查找匹配的变量。

把恰好是函数标识符的变量inner作为返回值返回回来,每次函数outer被调用的时候,函数inner都会被重新定义,如果它不被当做变量返回的话,每次执行过后它将不复存在。

在python里,函数就是对象,它也只是一些普通的值而已。也就是说你可以把函数像参数一样传递给其他的函数或者说从函数了里面返回函数

return内层函数时不加括号,只返回函数的地址:

代码:

#encoding=utf-8

def outer():
    name="python"

def inner():#outer函数内部定义的函数
        return name
    return inner#返回该内部函数

print outer()

 结果:

此时执行外层函数outer(),返回的是内层函数的函数引用(函数名称)--inner,想要执行内层函数,需要在outer()后边再加个括号,即outer()(),才会让内层函数执行

代码:

#encoding=utf-8

def outer():
    name="python"

def inner():#outer函数内部定义的函数
        return name
    return inner#返回该内部函数

print outer()()

结果:

函数作为变量:

例子:

#encoding=utf-8

def add(x,y):
    return x+y

def sub(x,y):
    return x-y

def apply(func,x,y):
    return func(x,y)

print "apply(add,2,1):",apply(add,2,1)
print "apply(sub,2,1):",apply(sub,2,1)
结果:

apply函数准备接收一个函数的变量,它也只是一个普通的变量而已,和其他变量一样。然后我们调用传进来的函数:“()代表着调用的操作,并且调用变量包含的值”。

在函数外,我们也能看到传递函数并没有什么特殊的语法,函数的名称只是和其他变量一样的表标识符而已。

闭包的理解:

先看个例子

#encoding=utf-8

def outer():
    name="python"
    def inner():
        print name
    return inner

res=outer()
res()
print res.func_closure#打印闭包里包含哪些外部变量
结果:

例中,inner作为一个函数被outer返回,保存在变量res中,并且还能够调用res()。为什么能调用呢?

通过上面变量的作用域和生存周期我们不难明白,name是函数outer里的一个局部变量,也就是说只有当outer正在运行时,该变量才会存在。

根据python的运行模式,我们是没法在函数outer执行退出之后还能继续调用inner函数的,并且在inner函数被调用时,变量name早已不存在了,但是为什么我们调用成功了呢?

这就回到了我们的闭包这个问题上了,python支持一个叫函数闭包的特性。

啥是闭包?

如果一个函数定义在另一个函数的作用域内,并且引用了外层函数的变量,则该函数称为闭包。闭包是Python所支持的一种特性,它让在非global scope定义的函数可以引用其外围空间中的变量,这些外围空间中被引用的变量叫做这个函数的环境变量。环境变量和这个非全局函数一起构成了闭包。

上例中的inner()函数就是一个闭包,它本身也是一个函数,而且还可以访问本身之外的变量。这能够通过查看函数的func_closure属性得出结论,这个属性里面包含封闭作用域里面的值(只会包含被捕捉到的值,比如name,如果在outer里面还定义了其他的值,封闭作用域里面是不会有的)

每次函数outer被调用时,inner函数都会被重新定义,上面每次返回的函数inner结果都一样,因为name没变。

如下例所示,我们将函数稍微改动一下,结果就不一样了

代码:

#encoding=utf-8

def outer(name):
    def inner():
        print name
    return inner

res1=outer("python")#返回闭包
res2=outer("java")#返回闭包
res1()#执行函数
res2()
结果:

分析:

在之前的例子中

def outer():
    name="python"
    def inner():
        print name
    return inner

外层函数后运行后,返回一个函数+函数需要的变量

name = "python"

def inner() :

print name

上边三行是整体返回的内容

如果在外层函数再加个外部的整形变量,在里面的函数中引用:

#encoding=utf-8

def outer():
    name="python"
    nbr=12
    def inner():
        print name
        print nbr
    return inner#不加括号就是返回函数对象,不是函数调用

res=outer()
res()#调用inner函数
print res.func_closure#打印闭包里包含哪些外部变量
结果:

D:\>python test.py
python
12
(<cell at
0x0000000004E56CA8: str object at 0x0000000004E58760>, <cell at
0x0000000004E56F78: int object at 0x0000000004E362C0>)

其中res = outer()是把inner函数对象赋值给res,因为没有括号,所以不是调用而是返回个函数对象

res()是调用inner函数

print res.func_closure是打印闭包里包含哪些外部变量,可以看到结果里有两个:即python和12

(<cell at 0x0000000004E56CA8: str object at 0x0000000004E58760>, <cell at 0x0000000004E56F78: int object at 0x0000000004E362C0>)

闭包特点:

一个函数返回的函数对象,这个函数对象执行的话依赖非函数内部的变量值,这个时候,函数返回的实际内容如下:
1 函数对象
2 函数对象需要使用的外部变量和变量值

以上就是闭包

闭包必须嵌套在一个函数里,必须返回一个调用外部变量的函数对象,才是闭包

 

在上边的例子中,相对于inner来说 ,outer函数就是它得全局变量,就好像你存粹写个函数会用到函数外面环境定义得全局变量一样 ,都是相对的概念

通俗理解就是:里面函数执行  ,需要用到外面函数的一个变量 ,所以,就把外面变量和里面这个函数合到一块,合到一块的这两个东西就是闭包

python中函数嵌套、函数作为变量以及闭包的原理的更多相关文章

  1. [转]关于python中带下划线的变量和函数的意义

    Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就易于阅读, ...

  2. python中如何调用函数交换两个变量的值

    python中如何调用函数交换两个变量的值 所有代码来在python3.7.1版本实现 以下实例通过用户输入两个变量,并相互交换:  方法一: def swap(a,b): # 创建临时变量,并交换 ...

  3. python中的生成器函数是如何工作的?

    以下内容基于python3.4 1. python中的普通函数是怎么运行的? 当一个python函数在执行时,它会在相应的python栈帧上运行,栈帧表示程序运行时函数调用栈中的某一帧.想要获得某个函 ...

  4. 举例详解Python中的split()函数的使用方法

    这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下   函数:sp ...

  5. python中的map()函数

    MapReduce的设计灵感来自于函数式编程,这里不打算提MapReduce,就拿python中的map()函数来学习一下. 文档中的介绍在这里: map(function, iterable, .. ...

  6. 揭秘 Python 中的 enumerate() 函数

    原文:https://mp.weixin.qq.com/s/Jm7YiCA20RDSTrF4dHeykQ 如何以去写以及为什么你应该使用Python中的内置枚举函数来编写更干净更加Pythonic的循 ...

  7. (转)Python中的split()函数的用法

    Python中的split()函数的用法 原文:https://www.cnblogs.com/hjhsysu/p/5700347.html Python中有split()和os.path.split ...

  8. Python 函数对象-函数嵌套-名称空间与作用域-闭包函数

    今日内容: 1. 函数对象 函数是第一类对象: 指的是函数名指向的值可以被当中数据去使用 1.可以被引用 2.可以当做参数传给另一个函数 3.可以当做一个函数的返回值 4.可以当做容器类型的元素 2. ...

  9. Python中的lambda函数介绍

    Lambda函数,即Lambda 表达式(lambda expression),是一个匿名函数(不存在函数名的函数),Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lam ...

随机推荐

  1. TCP/IP具体解释--TCP首部的TimeStamp时间戳选项

    TCP应该是以太网协议族中被应用最为广泛的协议之中的一个,这里就聊一聊TCP协议中的TimeStamp选项.这个选项是由RFC 1323引入的,该C建议提交于1992年.到今天已经足足有20个年头.只 ...

  2. 如何注册Navicat for MySQL软件

    https://jingyan.baidu.com/article/6181c3e061ca18152ef153b6.html 给力的经验 在注册界面里面输入信息 名:随便输入 组织:随便输入 注册码 ...

  3. python序列元素引用容易出错的地方

    python序列分列表和元组,不同之处在于元组的元素不能修改.元组使用小括号,列表使用方括号.元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可.举个简单的例子,a1是一个元组,a2是一个列表 ...

  4. wordpress用Elementor拖拽生成酷炫页面

    很多朋友看到wordpress网站做得很高大上,想知道是怎么做到的,其实很简单,用Elementor就能拖拽生成酷炫页面,ytkah就直接上干货了. 1.安装Elementor,到wordpress后 ...

  5. what's the python之自定义模块和包

    模块自定义 上节说了有关模块的知识,当时所说的模块都是内置模块,现在来看自己定制的模块,即模块也可以自定义. 模块的自定义就是指写一段python文件,一般情况下里面包含了可执行的语句和函数的定义,其 ...

  6. MySQL group replication介绍

    “MySQL group replication” group replication是MySQL官方开发的一个开源插件,是实现MySQL高可用集群的一个工具.第一个GA版本正式发布于MySQL5.7 ...

  7. localStorage 不方便存储数组时的替代方法

    项目背景是需要将搜索历史存储到localStorage中, 需要存储id和name,每次存储时都需要在记录中多加一条,用数组push显然是比较好的方法,但localStorage不方便存储数据,于是就 ...

  8. vue在页面嵌入别的页面或者是视频2

    vue在页面嵌入别的页面或者是视频 以下是嵌入页面 <iframe name="myiframe" id="myrame" src="http: ...

  9. mysql数据具体操作

    1.建表操作 前面提到的是简单的建表,这里需要提到一下外键. create table userinfo2( id int auto_increment primary key, name ), ge ...

  10. 32-Python3 MySQL(mysql-connector)

    32-Python3 MySQL(mysql-connector) ''' 创建数据库连接 ''' import pymysql mydb = pymysql.connect( host = '127 ...