Monklof思考和写字的地方

记一个有关python全局变量和局部变量的有趣问题

2015-01-10

昨天写了一段类似的python代码:

code = """
s1 = a + b
s2 = c + d

def _sum():
    return s1 + s2

result = _sum()
"""

exec_globals = dict(a=1, b=2, c=3, d=4)
exec_locals = dict()

exec code in exec_globals, exec_locals

执行结果:

Traceback (most recent call last):
  File "global_local.py", line 14, in <module>
    exec code in exec_globals, exec_locals
  File "<string>", line 8, in <module>
  File "<string>", line 6, in _sum
NameError: global name 's1' is not defined

当时就纳闷了,我明明在前边定义过s1这个变量啊,为什么访问不到?

LEGB法则

我们知道python的作用域遵循的是一个叫做 LEGB作用域的法则,python查找一个变量时,从L->E->G->B:

  1. Local:本地作用域
  2. Enclosing function locals: 父函数的本地作用域,从内而外的搜
  3. Global(Module): 全局作用域,一般而言是模块内变量和用global声明的变量。
  4. Build-in(Python): 内置变量

很显然_sum()函数本地不包含s1这个变量,也没有函数包含它,也不是python内置的变量,难道s1不是全局变量!?

bingo!

什么样的变量是全局变量(global)?

只有在模块中定义的变量,或者在局部区域用 global 语句定义的变量才是全局变量!

在程序中,code不是模块,因此在code中生成的变量都不是global的,是local,通过这个程序可以验证这一点:

code = """
s1 = a + b
s2 = c + d
print "a in globals?: ", "a" in globals()
print "s1 in globals?: ", "s1" in globals()
print "s1 in locals?: ", "s1" in locals()
"""

exec_globals = dict(a=1, b=2, c=3, d=4)
exec_locals = dict()

exec code in exec_globals, exec_locals

结果:

a in globals?:  True
s1 in globals?:  False
s1 in locals?:  True

那么最开始那段程序改成这样就可以运行了:

code = """
global s1, s2
s1 = a + b
s2 = c + d
def _sum():
    return s1 + s2

result = _sum()
"""

exec_globals = dict(a=1, b=2, c=3, d=4)
exec_locals = dict()

exec code in exec_globals, exec_locals

print "exec_globals['s1']: ", exec_globals["s1"]
print "exec_locals: ", exec_locals

输出:

exec_globals['s1']:  3
exec_locals:  {'_sum': <function _sum at 0x1014bbaa0>, 'result': 10}

也证明了刚才所说的,python真是神奇。

2014-01-10

标签: #Python  

参与讨论

#1   HEAist 2015-01-20 02:16 评论

哈哈,呜呜,啦啦……

#2   balabala 2015-03-10 18:02 评论

咦,你是谁呀?

#3   monklof 2015-07-26 11:15 评论

@[balabala] 刘超,还记得否。。这是我不久前建的一个博客

评论一下

Captcha