文档章节

Python 内层名字空间访问外层名字空间中的变量

Konghy
 Konghy
发布于 2017/02/25 14:58
字数 945
阅读 91
收藏 0

某天,一位新来的同事问我,在 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 l

f = 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 l

f = Foo()
f.too()

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

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

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

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

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

© 著作权归作者所有

共有 人打赏支持
Konghy
粉丝 7
博文 22
码字总数 31889
作品 0
朝阳
程序员
我和Python的Py交易》》》》》》 命名空间的小弟作用域

命名空间的小弟作用域 在这要明确一个观点,在Python中万物皆对象,而变量指向的就是对象。 变量可以是 类名,函数名,储存数据的变量…… 对象可以是 类 ,被封装的一段代码(函数),数据…...

BarkingPig
08/01
0
0
python locals和globals

locals和globals 标记一下:Dive Into Python 内容 我们先偏离一下 HTML 处理的主题, 讨论一下 Python 如何处理变量。 Python 有两个内置的函数,locals和globals, 它们提供了基于 dictionary...

henosteven
2013/02/20
0
0
【函数】02、函数进阶

一、函数的返回值 In [4]: def add(x, y): ...: return x+y ...: In [5]: add(1, 2)Out[5]: 3 In [8]: def add(x, y): ...: return x+y ...: print(x+y) ...: In [9]: add(1, 2)Out[9]: 3 In......

xiexiaojun
2017/06/10
0
0
python locals globals

Python有两个内置的函数,locals() 和globals(),它们提供了基于字典的访问局部和全局变量的方式。 首先,是关于名字空间的一个名词解释。是枯燥,但是很重要,所以要耐心些。Python使用叫做...

Sophia_tj
2014/08/20
0
0
python核心编程--第十二章

12.2 模块和文件 如果说模块是按照逻辑来组织 Python 代码的方法, 那么文件便是物理层上组织模块的方法。因此, 一个文件被看作是一个独立模块, 一个模块也可以被看作是一个文件。 模块的文件...

fzyz_sb
2013/06/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

环境搭建之八-- 环境变量

sudo vim /etc/profile 在最下方追加: export JAVA_HOME=/usr/java/jdk1.7.0_80 export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export MA......

imbiao
1分钟前
0
0
枚举案例二 BILL_TYPE_BJ("BILL_TYPE", "bj", "布机单"),

package yt.gk.woserviceapi.common; import com.alibaba.fastjson.JSONObject; import java.util.ArrayList; import java.util.List; public enum ConstEnum { /** * 工单类型 */ BILL_TYPE......

泉天下
3分钟前
0
0
MySQL相关整理记录

如何查看MySQL的引擎情况? MySQL的不同的引擎对于事务的支持是不同的,InnoDB支持事务。 例如如下: show engines; show variables like '%storage_engine%'; 可参考: 如何查看mysql引擎相...

宸明
6分钟前
0
0
并发模型比较

Golang 的特色之一就是 goroutine ,使得程序员进行并发编程更加方便,适合用来进行服务器编程。作为后端开发工程师,有必要了解并发编程面临的场景和常见的解决方案。一般情况下,是怎样做高...

java知识分子
7分钟前
1
0
jenkins私库上进行web项目部署原理

1.jenkins私库上进行项目部署是外网进行部署 2.jenkins部署web项目时 admin和front 的项目 的代码 是从华为云/git库中拿过来. 3.而parent文件是公用的文件,在部署时都会以jar包的形式引用进行...

森火
7分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部