第九天python3 闭包、nonlocal、默认值的作用域
闭包
自由变量:未在本地作用域中定义的变量,例如定义在内存函数外的外层函数的作用域中的变量;
闭包:出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包;
示例1:
# -*- coding: utf-8 -*- def counter(): c = [0] print(id(c),"wai") def inc(): c[0] += 1 print(id(c),"nei") return c[0] return inc foo = counter() print(foo(),foo()) print(foo())
代码解析:
第四行不会报错,c已经在counter函数中定义过了,而且inc中的使用方式是为c的元素修改值,而不是重新定义;
第七行return inc 返回的是一个函数对象;
第八行打印1,2;调用函数对象;
第十行打印3,因为第九行的c和counter中的c不一样,而inc引用的是自由变量正式counter的函数;
这是python2中实现闭包的方式,pyton3还可以使用nonlocal关键字;
示例2:
上图代码使用global可以运行,但是这使用的是全局变量,而不是闭包;
如果要对普通变量的闭包,python3中可以使用nonlocal;
nonlocal关键字
使用了nonlocal关键字,将变量标记为在上级的局部作用域中定义,但不能在全局作用域中定义;
示例:
上图中count是外层函数的局部变量,被内部函数引用;内部函数使用nonlocal关键字声明count变量在上一级作用域中;
左边代码可以正常使用,且形成闭包,右边代码不能正常运行,变量a不能在全局作用域中;
默认值的作用域
为什么第二次调用foo函数打印的是[1,1]?因为函数也是对象,python把函数的默认值放在了属性中,这个属性就是是伴随着这个函数对象的整个生命周期;如果print(xyz) #NameError,当前作用域没有xyz变量;
如上图所示,函数的地址并没有变,就是说函数这个对象没有变,调用它,它的属性__defaults__中使用元组保存所有默认值;xyz默认值是引用类型,引用类型的元素变动,并不是元组的变化;
非引用类型例子
如上图所示:属性__defaults__中使用元组保存所有默认值,它不会因为在函数体内使用了它而发生改变;
可变类型默认值,如果使用默认值,就可能修改这个默认值;
方法一:使用影子拷贝创建一个新的对象,永远不能改变传入的参数;
如上图所示:函数体内,不改变默认值;xyz都是传入参数或者默认参数的副本,如果就想修改原参数,无能为力;
方法二:通过值的判断就可以灵活的选择创建或者修改传入对象,这种方式灵活应用广泛,很多函数的定义,都可以看到使用None这个不可变的值作为默认参数,可以说这是一种惯用法;
如上图所示:使用不可变类型默认值,如果使用缺省值None就创建一个列表,如果传入一个列表,就修改这个列表;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!
2019-06-27 基于yum安装CDH集群