原文标题:KNOW HOW CLOSURES INTERACT WITH VARIABLE SCOPE

比如说你现在想要对一组数字进行排序,同时希望提高一组数字的优先级使这组数字优先显示。这种模式在展示用户接口时非常有用,在展示用户接口时经常需要优先展示一些重要信息以及异常事件。

解决这类问题的一个常用方法是在调用排序方法时传递一个帮助方法作为关键字参数。帮助方法的返回值用于对列表中的每一个元素进行排序。帮助方法能够检查列表中的值是否属于优先显示数组。帮助方法的实例代码如下:

下面是一个简单应用:

这个帮助方法能够正常工作有3个原因:

  • Python支持闭包:方法可以引用包含它们的作用域内的变量(functions that refer to variables from the scope in which they were defined)。这就是为什么helper方法可以访问group参数。
  • 在Python中方法是第一类对象(first-class object), 这意味着你可以直接引用方法、将方法赋值给变量、作为参数将方法传递给另一个方法、在if语句或者表达式用比较方法。这就是为什么sort方法可以接收另一个方法作为参数。
  • Python针对元组有一套特殊的比较规则。Python中元组的比较是按照元组中每个元素进行比较的,首先比较第0个元素,然后比较第一个,然后第二个,一直比较下去。这就是为什么在helper方法中返回两个不同的元组。

如果帮助方法在返回以上元组之外还能返回元素是否出现在了优先数组中将会对调用者更有帮助。看起来在前面代码的基础上实现这个行为非常容易,只需要在将代码做如下调整即可:

执行代码:

排序正确但是found结果错误。这是为什么呢?

当你在一个表达式中引用变量时,Python解释器会按照以下顺序遍历所有作用域来找到参数引用:

  • 当前方法的作用域
  • 任何闭合作用域(例如其它外围方法)
  • 包含当前代码的模块的作用域(也叫 global作用域)
  • 内嵌作用域(例如len和str)

如果遍历完上面全部作用域还没有找到需要引用的名字,就会抛出一个NameError。

但是给变量赋值的顺序就不一样了。如果在当前作用域中已经定义了变量,那么这个变量就会直接获得新值。如果当前作用域中没有这个变量,那么Python会把赋值语句当作变量定义。这个新变量的作用域就是包含赋值语句的方法。

赋值语句的行为就解释了为什么sort_priority2 的返回值错误了。found变量在helper中被赋予了true,闭包中的赋值语句被认为是一个新变量,这不影响外面方法中的变量。

两个found的作用域:

这就是闭包bug。但是这又是希望的结果。这种行为可以有效的防止方法中的变量污染外部模块。否则方法内部的任意赋值语句都会影响全局变量。这样会产生很多噪音,还会引起奇怪的bug。

使数据可以被访问

Python 3:在Python 3中有一种特殊语法可以使闭包内的数据被提取出来。使用nonlocal语句可以指定一个变量的遍历方式是从上级开始遍历。唯一的限制就是nonlocal不能遍历到模块级别(防止污染全局变量)。

下面使用nonlocal语句重写上面的方法:

在此,nonlocal语句可以很清晰的将一个作用域的变量以入到另一个作用域。它是对global语句的一个补充,global指定全局变量。

然而,就像全局变量的反面模式一样(much like the anti-pattern of global variables),除了简单的函数,我不建议大家使用nonlocal。nonlocal的副作用很难被追踪。尤其是在一个非常长的方法中,nonlocal语句、赋值语句与相关的变量离的非常远的情况。

一旦nonlocal是的代码变复杂,你就需要考虑是否可以将代码打包成一个帮助方法。下面我修改前面的代码,不使用nonlocal以达到同样目的,代码有点长,但是更易于阅读:

Python 2:不幸的是,Python 2中根本就没有nonlocal关键字。为了达到同样目的,你需要利用Python的高级用法来实现一个变通方法。下面的代码实现并不友好,但却是Python中的常用方法。

就像前面解释的一样,Python会向上遍历found被引用的域以确定found当前的值。这里引起欺诈性就是found是一个列表,它的值非常易变。这意味着,一旦found被检索到,闭包方法就可以修改found的状态进而把值从内部作用域中传递出来(在这里使用 found[0] = True)。

除了使用列表,通过使用字典、集合、类的实例一样可以在域间传值。

注意事项:

  • 闭包方法可以在它们定义的作用域内引用任何变量;
  • 默认情况下,闭包方法不能给外部变量赋值;
  • 在Python 3中可以使用nonlocal语句指定修改闭包以外的变量;
  • 在Python 2中使用可变值变量来代替nonlocal语句;
  • 除了非常简单的方法外,避免使用nonlocal语句。

python choose语句作用_理解闭包是如何与变量作用域相互影响的相关推荐

  1. python标志变量_Python 中的 global 标识对变量作用域的影响

    global 标识用于在函数内部,修改全局变量的值. 我们可以通过以下规则,来判定一个变量到底是在全局作用域还是局部作用域: 变量定义在全局作用域,那就是全局变量. 变量在函数中定义,并且加了 glo ...

  2. python中点的作用_一分钟了解Python中“*”的作用

    一分钟了解Python中"*"的作用 在为函数传递参数和函数定义时使用参数的时候,时常会看到有和 *和**,下面分别讲解其作用. 调用函数时使用*和 ** 假设有函数 def te ...

  3. python break语句作用_Python

    Python break 语句 Python break语句,就像在C语言中,打破了最小封闭for或while循环. break语句用来终止循环语句,即循环条件没有False条件或者序列还没被完全递归 ...

  4. python条件语句作用_Python 条件语句

    Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空(null)值为tr ...

  5. python 条件语句实例_详解python 条件语句和while循环的实例代码

    详解python 条件语句和while循环的实例代码,逻辑,布尔,值为,结束,语句 详解python 条件语句和while循环的实例代码 易采站长站,站长之家为您整理了详解python 条件语句和wh ...

  6. python break语句作用_Python break语句详解

    Python break语句,就像在C语言中,打破了最小封闭for或while循环.break语句用来终止循环语句,即循环条件没有False条件或者序列还没被完全递归完,也会停止执行循环语句. bre ...

  7. python quit函数作用_初识Python之基础知识

    安装了Anaconda3以及Jupyter notebook后对Python中的一些基础语法.定义容器,对容器做增删改,定义及调用函数做了学习,并且在notebook中实践敲了代码 数据类型:字符串( ...

  8. 理解闭包的前置条件—— λ演算和作用域规则

    前言 这几天用Scala写了一堆流计算程序,在翻阅Scala文档时看到了闭包一节,不知怎么就回忆起了自己上大二时用JavaScript做创新项目的经历--因为JS闭包的原理对当时的我来说很费解,以至于 ...

  9. python signal模块作用_如何理解python中信号Signal?

    信号signal 是python进程间进行信号发送的一种机制,其原理是操作系统对进程的控制,是一种程序中断一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号. 那么singanl到底有什么用呢 ...

最新文章

  1. CV01-语义分割笔记和两个模型VGG ResNet的笔记
  2. RH124-3 目录结构_转
  3. SVN的安装笔记和要注意的问题
  4. 关于Android的应用程序的发布的学习(一)
  5. Blackfin DSP学习心得与参考资料
  6. mysql索引方式_MySQL数据库的索引方式
  7. 【干货】大数据驱动的因果建模在滴滴的应用实践
  8. 物联网云计算成本核算 小厂的出路在哪里
  9. Java通过Netty实现Websocket消息推送
  10. [转载] Python大数据文本分析及应用
  11. matlab如何创建元组_MATLAB图像处理:42:使用预定义滤波器过滤图像
  12. jpl数据下载_火星上的AI:喷气推进实验室(JPL)的Tom Soderstrom访谈
  13. java get与post区别_POST和GET区别
  14. 十分钟带你解读什么是Promise异步编程
  15. 【前端知识之JS】reduce()方法与使用
  16. 51学工坊整理|甲骨文Oracle数据库 21c来了,来看看有哪些创新技术
  17. 【电脑系统】制作U盘启动盘(适用win)
  18. 时间复杂度简述及例题
  19. 自动控制原理知识点梳理——6.线性系统的校正方法
  20. 双硬盘装双系统 (ubuntu)

热门文章

  1. plsql轻量版基本语法
  2. 前端学习(1401):多人管理21新增用户
  3. spring学习(12):使用junit4进行单元测试
  4. 第十九期:CIO不懂老板数字化转型的目的,因为老板也不知道自己想要什么
  5. java学习(46):无参带返回
  6. flume简介(大数据技术)
  7. JQ trigger触发a标签点击事件
  8. Mac 下安装配置 Python 开发环境
  9. html input file 置空,清空 HTML File Input
  10. 常用方法 DataTable转换为Entitys