博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 内层名字空间访问外层名字空间中的变量
阅读量:6452 次
发布时间:2019-06-23

本文共 1547 字,大约阅读时间需要 5 分钟。

hot3.png

某天,一位新来的同事问我,在 Python 的函数中,怎么定义一个像 C 语言中的 static 变量。就像这样:

void foo(void){    static int a = 0;        ...}

已经抛弃 C 好长时间了,现在工作和业余都在使用 Python,也习惯用 Python 去思考。被问到这个问题时,我一时还真不知道怎么回答,因为在使用 Python 的这么长时间里,我还真没有遇到过这样的需求。当然,Python 自身也不直接支持类似的语法,所以也不会这样去思考。

实际上,他是想要在函数中保持一个变量的状态。经过短暂的思考,我回答他,你可以定义一个全局变量,然后在函数中用 global 引用这个变量就可以。顺便我还告诉他,Python 没有原生的 static 变量支持,你应该换一下别的思路,程序并不一定非要这么设计。

过了一会,他又来找我,说用 global 关键字后程序有问题。无赖之下,只能看了看他写的代码,其大概是像下面这样:

class Foo(object):    def too(self):        l = 1        def moo():            global l            l = l + 1            print l        moo()        print lf = Foo()f.too()

我告诉他,你把 global 那一句去掉就可以了。过了一会他又说,还是不行。这个时候,我已经有些不耐烦了,怎么就不行了呢。于是我调试了上面代码,报错:

UnboundLocalError: local variable 'l' referenced before assignment

我马上意识到我忽略了一个问题,这里是一个嵌套名字空间。我的同事并没有定义一个全局变量,而是一个局部变量,但他却尝试用 global 关键字去引用,显然得到的结果会是全局变量没有定义。所以我告诉他,去掉 global 语句。我没有意识到里边还有一个嵌套的作用域,之前从来没有没有遇到过这种问题,所以也没太注意。

如果把程序改成下边这样,则可以正常运行:

class Foo(object):    def too(self):        l = 1        def moo():            print l        moo()        print lf = Foo()f.too()

当时我并没有意识到问题出在哪里,于是查了下资料,发现了如下的一些规则

  • 内部函数,不能修改全局变量但可以访问全局变量
  • 内部函数,在尝试修改同名全局变量时,Python 会认为它是一个局部变量,并引发 UnboundLocalError
  • 在内部函数修改同名全局变量之前尝试访问变量名称(如: print l; l = l + 1),也会引发 UnboundLocalError

所以问题涉及到一个作用域层次的问题,也就是 内层作用域可以访问外层作用域中的变量,但不能修改,一旦尝试修改,Python 则会认为该变量是一个局部变量。这样,问题就被解释了。

还需要注意的一点是,在 Python 中,只有模块,类以及函数才会引入新的作用域,其它的代码块是不会引入新的作用域的,即使有不同层次的缩进。

我没有仔细看同事的代码,不知道他具体要表达什么,我只是告诉他换一种设计思路。我觉得很多时候我们都应该这样,当你发现你的设计思路不符合语言习惯的时候,那说明你的设计是不正确,何不换换别的思路呢。

转载于:https://my.oschina.net/kuanghy/blog/846264

你可能感兴趣的文章
Javascript - 函数里传的是值还是引用?
查看>>
社区已正式上线屏蔽功能,不喜欢就「加灰」吧!
查看>>
Latex beamer书签乱码解决方法
查看>>
Python按行读取大文件
查看>>
改装智能锁,或是ofo“学习”摩拜的开始!
查看>>
7月3日云栖精选夜读丨数字化诗人:这可能是第一位用算法写诗的诺贝尔文学奖得主...
查看>>
正念奇迹(一则正能量)
查看>>
【DVWA】Web漏洞实战之File Upload
查看>>
JavaNIO基础02-缓存区基础
查看>>
ab 测试模块高并发
查看>>
教你如何避免威胁建模7大“坑”
查看>>
大咖 | 斯坦福教授骆利群:为何人脑比计算机慢1000万倍,却如此高效?
查看>>
IntelliJ IDEA自动导入包去除星号(import xxx.*)
查看>>
阿里 Blink 正式开源,重要优化点解读
查看>>
日本开设无人机专业,打造无人机“人才市场”
查看>>
win10和win server 2016新的TCP功能介绍
查看>>
Eclipse安装SVN客户端
查看>>
Ubuntu 16.04下使用Wine安装Windows版的微信(不太完美)
查看>>
区块链 | 如何投资区块链资产-《区块链历史链条》4
查看>>
北京供销大数据集团荣获“2016-2017年度数据中心优秀创新企业奖”
查看>>