文档章节

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

Konghy
 Konghy
发布于 2017/02/25 14:58
字数 945
阅读 67
收藏 0
点赞 0
评论 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 locals和globals

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

henosteven
2013/02/20
0
0
python locals globals

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

Sophia_tj
2014/08/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核心编程--第十二章

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

fzyz_sb
2013/06/17
0
0
Python提高笔记整理(一)

什么是GIL?GIL对多线程的影响 GIL全称Global Interpreter Lock(全局解释器锁)。GIL和Python语言没有任何关系,只是因为历史原因导致在官方推荐的解释器Cpython中遗留的问题。每个线程在执...

我是小谷粒
07/05
0
0
云计算Python自动化:Python变量详解

python学习过程中会用到许多数据,那为了方便操作,需要把这些数据分别用一个简单的名字代表,方便在接下来的程序中引用。 变量就是代表某个数据(值)的名称。简单点说变量就是给数据起个名字...

长沙千锋
05/16
0
0
Python Tutorial 实践(3)

今天终于有时间继续推进Python Tutorial的进程了。 本文主要是对官方Python Tutorial的第4节内容进行的分析。第4节主要是对Python中的一些控流程制语句进行了基本的介绍。 Python的if语句和其...

鄂世嘉
2013/05/01
0
0
django实例:用创建你的第一个应用投票系统

当然主要是从django的帮助文档里面来的,权当是翻译吧 这个投票系统的主要功能有 1、一个前台页面,可以让用户来投票 2、一个管理员页面,可以用来添加、修改、删除投票 首页第一步要确定你已...

DjangoChina
2013/06/01
0
0
Python迭代器生成器,私有变量及列表字典集合推导式(二)

1 python自省机制 这个是python一大特性,自省就是面向对象的语言所写的程序在运行时,能知道对象的类型,换句话说就是在运行时能获取对象的类型,比如通过 type(),dir(),getattr(),hasattr(),i...

善良小郎君
06/11
0
0
【译】自己动手写Django app,第一部分【完】

原文地址:https://docs.djangoproject.com/en/1.4/intro/tutorial01/ 让我们通过例子来学习。 通过这个教程,我们将带领你了解创建基本的调查程序。 它将包括两部分: 一个让人们可以查看调...

davidxp
2013/02/20
0
3

没有更多内容

加载失败,请刷新页面

加载更多

下一页

防火墙实例

3、一个包过滤防火墙实例 环境:redhat9 加载了string time等模块 eth0 接外网──ppp0 eth1 接内网──192.168.0.0/24 #!/bin/sh modprobe ipt_MASQUERADE modprobe ip_conntrack_ftp modp...

李超小牛子
2分钟前
0
0
TensorFlow 作用域与操作符的受限范围

variable_scope 影响变量和操作符 name_scope 只影响操作符 with tf.name_scope(""),使用空字符串将作用域返回到顶层 tf.variable_scope("") 相当于添加一个空层 import tensorflow as tf...

阿豪boy
12分钟前
0
0
Java面试基础篇——第六篇:常见Map类的区别

常见的map类有: HashMap, ConcurrentHashMap (Jdk1.8) , LinkedHashMap, TreeMap, Hashtable。 其中我们最常用的莫过于HashMap, 和并发情况下使用的ConcurrentHashMap了,它们的主要区别就在...

developlee的潇洒人生
14分钟前
0
0
崛起于Springboot2.X之前端模版freemaker(23)

1、配置文件 spring: freemarker: allow-request-override: false cache: true check-template-location: true charset: UTF-8 content-type: text/html ......

木九天
31分钟前
1
0
spring-boot:run启动时,指定spring.profiles.active

Maven启动指定Profile通过-P,如mvn spring-boot:run -Ptest,但这是Maven的Profile。 如果要指定spring-boot的spring.profiles.active,则必须使用mvn spring-boot:run -Drun.profiles=test......

夜黑人模糊灬
33分钟前
0
0
大数据分析挖掘技术学习:Python文本分类

引言 文本分类作为自然语言处理任务之一,被广泛应用于解决各种商业领域的问题。文本分类的目的是将 文本/文档 自动地归类为一种或多种预定义的类别。常见的文本分类应用如下: • 理解社交媒...

加米谷大数据
37分钟前
0
0
istio-0.8 指标监控,prometheus,grafana

配置: https://istio.io/docs/tasks/telemetry/metrics-logs/ https://istio.io/docs/tasks/telemetry/tcp-metrics/ envoy拦截请求>上报mixer>对接prometheus>grafana 效果截图: promethe......

xiaomin0322
39分钟前
0
0
公众号推荐

阿里技术 书籍:《不止代码》

courtzjl
42分钟前
0
0
关于改进工作效率

1.给不同的业务线建立需求群,所有的数据需求都在群里面提。 2.对于特别难搞定的事情,到对应的技术哪去做,有问题随时沟通。 3.定期给工作总结形成方法论。 4.学习新的技术,尝试用新的方法...

Avner
49分钟前
0
0
关于thinkphp 框架开启路径重写,无法获取Authorization Header

今天遇到在thinkphp框架中获取不到header头里边的 Authorization ,后来在.htaccess里面加多一项解决,记录下: <IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews Rewrite......

殘留回憶
52分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部