Python嵌套函数 闭包

Stella981
• 阅读 615

1. 什么是嵌套函数

  嵌套函数就是在函数中定义函数,英文叫nested function

def outer(x):    def inner():        print(x)    inner()

这也很好理解,在函数outer中定义了另外一个函数inner,而inner也必须在outer中被调用才能执行。

我们还可以直接把内容定义的函数当做返回值:

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

这样outer这个函数其实返回的是None,它只是会打印出输入参数x的值

outer(10)>>> 10

当然,也有的地方直接返回函数名,而不是返回函数的执行结果:

def outer2(x):    def inner(y):        print(x+y)    return inner

这是由于我们返回的是函数名,因此在使用的时候,后面需要跟参数:

foo = outer2(10)foo(5)>>> 15

2. 变量作用域

  两个函数处于不同的层次,肯定会有作用域的问题,关于Python中的作用域,网上的文章一大堆,这里我们说一下初学者们可能会忽略的东西。Python的函数中是不能对全局变量进行赋值,只能读取全局变量的值,但listdict除外,这是因为list和dict都是可变类型,而Number、String、Tuple和Sets这些都是不可变类型。

a = 1def inc():    a += 1    return ainc()

执行这段代码就会提示:

UnboundLocalError: local variable 'a' referenced before assignment
  • 但如果我们在函数内部把全局变量a的值打印出来,不去对它进行写操作:

    a = 1def prt():    print(a)prt()

这段代码是可以正确执行的。

  • 如果我们就是想在函数中修改全局变量的值,可以使用global关键字:

    a = 1def inc():    global a    a += 1    return ainc()

  • 如果在函数中重新定义一个名字一样的变量:

    a = 1def inc():    a = 2    return aprint(inc())print(a)>>> 2>>> 1

这样的话,函数内部定义的变量a只是个局部变量,它是不会影响到全局变量a的。

  • 如果我们操作的是list:

    a = [1]def inc():    a[0] += 1    return a[0]inc()

这段代码是可以执行的,我们也可以为list中添加其他元素:

a = [1]def inc():    a.append(2)    return ainc()
  • 如果重新定义相同名字的list,也只会是局部变量,不影响全局的list:

    a = [1]def inc():    a = [2,3]    return aprint(inc())print(a)>>> [2, 3]>>> [1]

  • 嵌套函数的变量作用域跟上面所讲的基本是一致的,只是如果内部的函数想使用外部函数的变量,需要使用关键字nonlocal

    def outer():    a = 10    def inner():        nonlocal a        a += 1        print(a)    inner()outer()>>> 11

3. 闭包

  说到嵌套函数,就必须要讲闭包,英文是Closures,什么是闭包?百度百科的解释如下:

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

如何创建闭包?需要满足下面三点:

  • 闭包函数必须有内嵌函数

  • 内嵌函数需要引用该嵌套函数上一级中的变量

  • 闭包函数必须返回内嵌函数

所以我们在上面定义的outer2中的inner(),就会形成一个闭包。我们把前面的例子在展示一遍:

def outer2(x):    def inner(y):        print(x+y)    return innerfoo = outer2(10)foo(5)>>> 15

为什么叫闭包呢?因为即便我们把outer2删除调,再执行foo()也是有效的,不会因为离开它的执行空间而被销毁导致无迹可寻。

del outer2foo(6)>>> 16

闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象一一保存了这个闭包中所有的外部变量。

foo.__closure__>>> (<cell at 0x0000000004FE4408: int object at 0x00000000734D6D60>,)foo.__closure__[0].cell_contents  >>> 10

其他函数也有__closure__属性,只不过都是None。

4. 什么时候使用闭包

  闭包可以避免使用全局值,并提供某种形式的数据隐藏,也提供了一种面向对象的解决方案。

  当一个类只包含一个方法,此时比较适合使用闭包。但如果类中包含的方法比较多,还是直接使用class来定义比较合适。

def make_multiplier_of(n):    def multiplier(x):        return x * n    return multiplier

闭包的使用:

# Multiplier of 3times3 = make_multiplier_of(3)# Multiplier of 5times5 = make_multiplier_of(5)

Python嵌套函数 闭包

Python高性能系列文章

  1. Python高性能计算之列表

  2. Python高性能计算之字典

  3. Python高性能计算之堆

  4. Python高性能计算之字典树

  5. Python常用操作的复杂度

欢迎关注微信公众号:Quant_TimesPython嵌套函数 闭包

本文分享自微信公众号 - 科学计算Tech(Quant_Times)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
JS 闭包(内存溢出与内存泄漏)(垃圾回收机制)
1.有关闭包定义闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量闭包的特性:函数内再嵌套函数内部函数可以引用外层的参数和变量参数和变量不会被垃圾回收机制回收
Stella981 Stella981
2年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Stella981 Stella981
2年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Stella981 Stella981
2年前
Sass
嵌套规则(NestedRules)Sass允许将一套CSS样式嵌套进另一套样式中,内层的样式将它外层的选择器作为父选择器mainp{color:00ff00;width:97%;.redbox{
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这