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

下面我简述一下:

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

# 修改下面这个函数

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

这样当然是错的, 因为整数是不可变对象,当你作为参数传进去时都会创建一个新的内存空间。

虽然失败了,但也让我想到一个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变量,并且指向了不同的值。如下图所示:

再来看下面这个例子:

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变量来赋值。

画个图就很好懂了。

在这个例子中, 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上看看大佬们的回答。很有学习的价值。

文源网络,仅供学习之用,侵删。

在学习Python的道路上肯定会遇见困难,别慌,我这里有一套学习资料,包含40+本电子书,800+个教学视频,涉及Python基础、爬虫、框架、数据分析、机器学习等,不怕你学不会!

https://shimo.im/docs/JWCghr8prjCVCxxK/ 《Python学习资料》

关注公众号【Python圈子】,优质文章每日送达。

python闭包技巧_案例详析:Python闭包与nonlocal关键字相关推荐

  1. python编程入门与案例详解-Python程序设计案例课堂

    Python程序设计案例课堂 第Ⅰ篇 基础知识 1 揭开Python神秘面纱 1.1 什么是Python 1.2 Python的优点和特性 1.2.1 Python的优点 1.2.2 Python的特 ...

  2. python编程入门与案例详解-python编程入门知识练习

    python 入门基础知识练习 1编写第一个程序,目前使用的都是python 3 # print('hello world!') 2.查看当前python编辑器的版本号 # python -v 3.使 ...

  3. python面试技巧_经典7大Python面试题!看完考官竟然给了我30k的薪资

    Python面试(一)之交换变量值 平时时不时会面面实习生,大多数的同学在学校里都已经掌握了Python.面试的时候要求同学们实现一个简单的函数,交换两个变量的值,大多数的同学给出的都是如下的答案 实 ...

  4. 什么是python编程例子_案例详解:优化Python编程的4个妙招

    全文共3510字,预计学习时长7分钟 作为数据科学家,敲出最优的Python代码非常非常重要.别无他法,杂乱低效的代码笔记本会消耗你的时间,也会浪费大量项目资金.经验丰富的数据科学家和专业人士都很清楚 ...

  5. python编程入门与案例详解-Python爬虫天气预报实例详解(小白入门)

    本文研究的主要是Python爬虫天气预报的相关内容,具体介绍如下. 这次要爬的站点是这个:http://www.weather.com.cn/forecast/ 要求是把你所在城市过去一年的历史数据爬 ...

  6. python背诵技巧_精选22个Python实用技巧,秀技能必备这份技术列表!

    被人工智能捧红的 Python 已是一种发展完善且非常多样化的语言,其中肯定有一些你尚未发现的功能.那么今天或许我能够让你学到一些新技巧. Python的发展: "人生苦短,我用 Pytho ...

  7. python多线程原理_代码详解Python多线程、多进程、协程-阿里云开发者社区

    云栖号资讯:[点击查看更多行业资讯] 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 一.前言 很多时候我们写了一个爬虫,实现了需求后会发现了很多值得改进的地方,其中很重要的一点就是爬 ...

  8. python内存技巧_使用__slots__节省python内存技巧

    __slots__作用 __slots__有一个作用是:限制类实例绑定的属性,但是它有一个更重要的作用就是节省内存,当然更适用于数据量大的情况(万量级以上). __slots__节省内存的原理 cla ...

  9. python编程入门与案例详解-Python零基础必看的入门书藉:Python编程从入门到实践...

    提取码:sc9i 本书是一本针对所有学习Python读者而作的Python 入门书.全书分两部分:第一部分介绍用Python编程所必须了解的基本概念,包括matplotlib.NumPy 和Pygal ...

最新文章

  1. 条件注释判断浏览器!--[if !IE]!--[if IE]!--[if lt IE 6]!--[if gte IE 6]
  2. Spring Boot spring mvc 拦截器
  3. 【HTTP协议】超详细的HTTP协议详解
  4. 怎么打包图片_怎么将许多张照片打包发到邮箱?
  5. 如何在设计项目中使用冷调酷色
  6. asp.net web.config连接mysql数据库_ASP.NET中使用web.config配置数据库连接
  7. 网络工程师 名词解释
  8. 树莓派处理温湿度监控,红外蔽障传感器,超声波测距传感器,激光传感器,有害气体检测,人体感应器,倾斜开关,雨滴传感器,土壤监测
  9. 三维计算机学校,什么是三维虚拟校园系统?
  10. 1336:【例3-1】找树根和child
  11. 马云回应豪宅谣言;淘宝上线了三架波音747进行拍卖;迪拜投1.4亿美元建模拟火星丨价值早报
  12. CentOS8配置yum/dnf镜像源
  13. IT人才外包服务的好处?
  14. linux下qt触摸屏没反应怎么办,QT移植后触摸屏无法使用(不好使)的解决办法!!!...
  15. Linux下查看CPU、内存、磁盘使用情况,并计算其使用率
  16. 吃货程序猿怎么区分低热量食品
  17. 微信小程序实现跑马灯效果(完整代码)
  18. Go-ecc加密解密详解与代码
  19. 奔腾cpu可以安装黑苹果吗_你还在为安装黑苹果而烦恼吗?
  20. 实验24:超声波测距仪小实验

热门文章

  1. c++数学函数运算,浮点数据相等判断
  2. linux文档采集前五行,Linux 学习-Shell筛选top前五行信息
  3. MYSQL中HEX、UNHEX函数
  4. C++ set简介及简单应用
  5. codeforces 796A-D
  6. UITextField 对比 UITextView
  7. node.js抓取数据(fake小爬虫)
  8. 多线程并发思考--文件加锁
  9. [转载] [转载] python set集合如何有序输出_python set集合的用法
  10. [转载] JAVA中分为基本数据类型及引用数据类型