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

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

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

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

4801f32a7a21bf95b58c24b0eaa25423.png

下面是一个简单应用:

1a11c1f7812f276f3f4c80b5a3d3ee90.png

这个帮助方法能够正常工作有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方法中返回两个不同的元组。

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

083c50def353550b8d876e8b42fc3128.png

执行代码:

565afdb637a080162818894e1172ab7d.png

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

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

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

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

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

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

两个found的作用域:

57021037dd05bd33984629daeb75147e.png

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

使数据可以被访问

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

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

0b4a6f92017a741a8cfeec38e550d777.png

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

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

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

b6eb91c95ef15ed2249c2e5187dc1ae6.png

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

967ea5d7469a39c3a682a26a8a7c9f05.png

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

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

注意事项:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420193.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习(1368):app.use使用

const express require(express);const app express(); app.use((req, res, next) > {console.log(请求走了use中间件);next(); }) app.use(/request, (req, res, next) > {console.log(请求走了use中间件/hh)next() }) app.get(/list, (req, res) > {//send 响应内…

JDE Client开发端 左侧边栏设置

转载于:https://www.cnblogs.com/GYoungBean/p/4299317.html

cmd oracle 连接实例_C#连接Oracle数据库的实例方法

1.建立连接字符串,里面包含数据库名称、用户名和密码2.建立操作字符串,里面是对数据操作的SQL语句3.建立Connection,用连接字符串作为参数建立4.建立Command,用操作字符串和Connection作为参数5.建立DataAdapter,用Com…

59-混沌操作法感悟2.(2015.2.25)

混沌操作法感悟2羊年到了,今年要好好努力,争取赚到满意的收入。今天刚来到上海,明天开始上班,今天更新下春节期间在家的思考。随机性被视为噪音是因为时间因素,时间框架的长短性。如果以小时为时间框架,这种…

insert事务隔离mysql_MySQL数据库详解(三)MySQL的事务隔离剖析

提到事务,你肯定不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转 100 块钱,而此时你的银行卡只有 100 块钱。转账过程具体到程序里会有一系列的操作,比如查询余额…

前端学习(1369):中间件应用

const express require(express);const app express(); app.use((req, res, next) {res.send(网站维护中); }) app.use(/admin, (req, res, next) > {let isLogin false;if (isLogin) {next()} else {res.send(你还没有登录);} }) app.get(/admin, (req, res) > {res.…

宽容与忍耐 忍乃济——这是《尚书》这部中国令世人刮目的奇书告诉我们的真理 保身第一法:谦逊;处事第一法:安详;待人第一法:涵容(宽容);养心第一法:洒脱...

宽容与忍耐 不让古人,是谓有志;不让今人,是谓无量。 忍耐若与敏感、魄力、思维、迅速行动结合,将所向无敌。 脾气服从理性的判断才会成功,否则只是动物式愤怒欲的满足.或从心理学的角度讲是怒需求。 大智者…

mysql数据表交叉引用_数据定义语句

数据定义语句MySQL 8.0支持原子数据定义语言(DDL)语句。此功能称为原子DDL。原子DDL语句将数据字典更新,存储引擎操作和与DDL操作相关联的二进制日志写入操作组合到单个原子事务中。即使事务在操作期间停止,事务也可以提交,并在数据字典&…

前端学习(1370):错误处理中间件

const express require(express);const app express(); app.get(/index, (req, res) > {throw new Error(程序发生了错误);/* res.send(); */ }) app.use((err, req, res, next) > {res.status(500).send(err.message); }) app.listen(3000); console.log(服务器启动成…

MySQL官方备份_Mysqlbackup 备份详解(mysql官方备份工具)

A.1全库备份.命令:mysqlbackup--defaults-file/home/mysql-server/mysql3/my.cnf --userroot --passwordroot --databases"mysql total2" --with-timestamp --backup-dir/home/mysql-server/backup backup参数说明:--defaults-filemy.cnf文件的路径…

Linux下的库文件搜索路径

对于以压缩包发布的软件,在它的目录下通常都有一个配置脚本configure,它的作用确定编译参数(比如头文件位置、连接库位置等),然后生成Makefile以编译程序。可以进入该软件的目录,执行"./configure --help"命令查看使用帮…

慕课笔记 mysql读写分离_mysql读写分离笔记

主数据库执行命令:show master status;得到结果mysql-bin.0000092123从数据库执行命令stop slave;change master tomaster_host47.95.247.135,master_port3306,master_userroot,master_passwordroot,master_log_filemysql-bin.000009,master_log_pos4353;start slav…

ruby记录

ruby记录 --posted on 2015-02-28 20:52 zlingh 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/zlingh/p/4306195.html

前端学习(1372):构建模块化路由

const express require(express);const app express(); //创建路由对象 const home express.Router(); app.use(/home, home); home.get(/index, (req, res) > {res.send(欢迎来到我的页面) }) app.listen(3000); console.log(服务器启动成功); 运行结果

做移动端视频通话软件,大致看了下现有的开源软件(转)

转自:链接 要做一个移动端视频通话软件,大致看了下现有的开源软件一) sipdroid1)架构sip协议栈使用JAVA实现,音频Codec使用skype的silk(Silk编解码是Skype向第三方开发人员和硬件制造商提供免版税认证(RF)的Silk宽带音…

wamp环境搭建到mysql就不成功_Wamp环境搭建常见错误问题解决

第一点、对于apache php mysql 的版本的正确选择问题:网上有些教学视频已经很早了,然后很多人照着来,完全和视频里讲的一样,但是结果就是搭建不成功。出现问题原因:三件套的版本选择不正确,比如有的php版…

前端学习(1373):构建模块化路由2

demo37.js const express require(express);const app express(); const home require(./home); const admin require(./admin);app.use(/home, home); app.use(/admin, admin);app.listen(3000); console.log(服务器启动成功); home.js const express require(express…

WebApi权限验证流程的设计和实现

前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问,本文通过Form认证,Mvc的Controller基类及Action的权限验证来实现Web系统登录&am…

前端学习(1374):express参数中get参数的获取

const express require(express);const app express(); app.get(index, (req, res) > {res,end(req.query); })app.listen(3000); console.log(服务器启动成功); 运行结果

mysql二维数据转一维存_二维数组转一维数组

//二维转一维var arr[[1,2,3],[2,5,6,7],[234,234,545]]function dir(arr) {var result[];for(var r0;rfor(var c0;cresult.push(arr[r][c])}}return result;}console.log(dir(arr))//方法二function dir2(arr) {var result[];for(var r0;rresultresult.concat(arr[r])}return …