python2 nonlocal_python unboundlocalerror

python2 nonlocal_python unboundlocalerror在廖雪峰的官网上看到一个很有意思题目。关于闭包的,有兴趣的朋友可以看一下这里,做一下这个题目,当然需要一点闭包的知识。下面我简述一下:利用闭包返回一个计数器函数,每次调用它返回递增整数。#修改下面这个函数defcreateCounter():defcounter():passreturncounter#测试:counterA=createCounter()print(counter…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

在廖雪峰的官网上看到一个很有意思题目。关于闭包的,有兴趣的朋友可以看一下这里, 做一下这个题目,当然需要一点闭包的知识。下面我简述一下:

利用闭包返回一个计数器函数,每次调用它返回递增整数。

# 修改下面这个函数

def createCounter():

def counter():

pass

return counter

# 测试:

counterA = createCounter()

print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5

counterB = createCounter()

if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:

print(‘测试通过!’)

else:

print(‘测试失败!’)

方法一

说实话这题对我来说还是有点难度的,但我尝试了几次之后也找到一个比较track的方法。一开始我是这么写的。

def createCounter():

i = 0

def counter(i=i):

i = i+1

return i

return counter

# 执行结果是: 1 1 1 1 1

这样当然是错的, 因为整数 是 不可变对象,当你作为参数传进去时都会创建一个新的内存空间,这里边其实还有很多学问,不是很了解的可以看一下stackoverflow上的这个回答。虽然失败了,但也让我想到一个track的方法,就是把i换成可变对象

def createCounter():

i = [0]

def counter():

i[0] = i[0]+1

return i[0]

return counter

# 执行结果是: 1 2 3 4 5

OK, 这样就没有问题了。但这并不是一个好的解决方法, 利用可变对象的这个特性有可能会引起变量作用域混乱的。于是我又想到了另一种解决。

方法二

另一种方法就是使用generator,在createCounter函数下创建一个从1开始的整数generator, 然后在cuonter函数中调用。由于generator保存的是算法,当调用next函数时就可以计算出下一个的值,直到没有元素报错。当然这里不用担心,generator可以创建无限集合。

def createCounter():

def inter():

n = 1

while True:

yield n

n = n+1

f = inter()

def counter():

return next(f)

return counter

上面的代码中,inter()就是一个包含从1开始的所有整数的generator。然后在counter里边调用。每次计算下一个的值。这样就可以实现计数的功能。说到generator,stackoverflow上有一个回答值得一读,即使你已经掌握这个也可以读一下,这个回答应该还是python问答当中排名第一的。链接在这里。

方法三

emmmm,想到这两种方法已经是极限了,于是我往评论区翻了翻,看一下大佬们有什么做法。然后就看到一个我没见过的关键字…其中有一个大佬是这么做

def creat_counter():

i=0

def counter():

nonlocal i

i=i+1

return i

return counter

学了python这么久,第一次看到nonlocal这个关键字,果然我还是太菜了。。。

不过从语句上看nonlocal的作用应该是把i变成全局变量,这样每次修改都可以生效,跟global关键字有点像。既然找到一个知识盲点,那就将它彻底解决吧。

nonlocal 与 global

说了这么多,是时候回到主题了,nonlocal关键字到底是什么?在什么情况下用呢?简单来说,nonlocal关键字是用来改变变量的作用域的,直接解释不太好懂。先来看两个例子吧。

def outside():

msg = “Outside!”

def inside():

msg = “Inside!”

print(msg)

inside()

print(msg)

执行结果是什么呢?

Inside!

Outside!

结果应该很好理解, 在outside函数里面定义了inside函数并且执行。当运行outside函数时,inside里面的msg变量指向了”Inside!”,outside里面的msg指向了”Outside!”, 也就是说这里其实有两个msg变量,并且指向了不同的值。如下图所示:

python2 nonlocal_python unboundlocalerror

变量示意图

再来看下面这个例子:

def outside():

msg = “Outside!”

def inside():

nonlocal msg

msg = “Inside!”

print(msg)

inside()

print(msg)

现在的执行结果就变成了:

Inside!

Inside!

两段代码之间的差别仅在于下面的例子多了一句 nonlocal msg。这里的nonlocal关键字起到了什么作用呢?nonlocal意思是告诉python,不要重新创建msg变量,而是使用outside中的msg变量来赋值。画个图就很好懂了。

python2 nonlocal_python unboundlocalerror

变量示意图

在这个例子中, msg变量只被创建了一次,首先将”Outside!”赋值给msg,然后将”Inside!”赋值给了msg, 此时的msg已经指向了”Inside!”。因此执行的结果两个都是”Inside!”。

现在我们知道了,nonlocal是用来改变变量的作用域的。本例中,nonlocal将inside函数里面的msg变量的作用域变成了outside块中的区域。nonlocal跟global 这两个关键字非常像,不同之处在于nonlocal用于外部函数作用域的变量,而global用于全局范围内的变量。

这就是nonlocal关键字的作用。但是还有一点值得注意,先看下面的例子。

def outside():

d = {“outside”: 1}

def inside():

d[“inside”] = 2

print(d)

inside()

print(d)

大家觉得输出是什么呢?

实际输出是这样的:

{‘outside’: 1, ‘inside’: 2}

{‘outside’: 1, ‘inside’: 2}

原因嘛,当然是因为dict是可变对象了,但由于 d[“inside”] = 2 这样的语句是有点让人迷惑的,看起来很像重新赋值。实际上dict的赋值是调用了setitem方法。这样看就不会感到迷惑了。

# 下面的代码是等价的。

d[“inside”] = 2

d.__setitem__(“inside”, 2)

关于nonlocal关键字,应该讲清楚了吧。至于python的闭包,其实还是挺复杂的,上面的只是几个例子,想要更加深入的学习可以上stackoverflow上看看大佬们的回答。很有学习的价值。

写文不易, 还请大家多多支持!

参考资料:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/196716.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • cas算法是什么_对算法的认识

    cas算法是什么_对算法的认识应用原子操作类,例如AtomicInteger,AtomicBoolean …适用于并发量较小,多cpu情况下;Java中有许多线程安全类,比如线程安全的集合类。从Java5开始,在java.util.concurrent包下提供了大量支持高效并发访问的集合接口和实现类。如:ConcurrentMap、ConcurrentLinkedQueue等线程安全集合。引入问题那么问题来了,这些线程安全类的底层是怎么保证线程安全的,你可能会想到是不是使用同步代码锁synchronized?引入概念这些线

    2022年8月8日
    3
  • Java开发手册之代码格式

    Java开发手册之代码格式Java开发手册之代码格式

    2022年4月22日
    42
  • pg数据库杀进程_centos杀死进程命令

    pg数据库杀进程_centos杀死进程命令SELECTpg_stat_get_backend_pid(s.backendid)ASprocpid,      pg_stat_get_backend_activity(s.backendid)AScurrent_query   FROM(SELECTpg_stat_get_backend_idset()ASbackendid)ASs;  杀掉某个

    2025年9月14日
    14
  • LAN8720A网络模块关于时钟的使用问题「建议收藏」

    LAN8720A网络模块关于时钟的使用问题「建议收藏」微雪的LAN8720A驱动电路:正点原子LAN8720A驱动电路:1、nINTSELConfiguration从原理图中可以看出正点原子的LAN8720A模块所使用的晶振是25M,而微雪的LAN8720A模块使用的晶振是50M,根据数据手册和结合原理图可以看出,微雪的LAN8720A的nINTSEL没有接下拉,则是默认使用内部上拉到高电平,即nINTSEL=1,为REF_CLKInMode模式,所以选用50M的晶振。…

    2022年6月22日
    154
  • 详尽介绍的意思_aboutconfig怎么进去

    详尽介绍的意思_aboutconfig怎么进去一、什么是about:configabout:config:是Firefox的设置页面,Firefox提供了不少高级设置选项在这里以便让你可以更加详细地控制Firefox的运行方式。官方不推荐

    2022年8月1日
    7
  • Python写入Excel文件-多种实现方式(测试成功,附代码)

    目录xlsxwriter库储存数据到excel简介示例:写入excel更多添加工作表样式:写入单元格数据插入图片写入超链接插入图表pandas库储存数据到excel简介示例:写入excelopenpyxl库储存数据到excel示例:写入excel更多打开已有文件根据数字得到字母,根据字母得到数字删除工作表查看表名和选择表(sheet)设置单元格风格xlsxwriter库储存数据到excel简介功能比较强:支..

    2022年4月3日
    419

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号