python 的变量作用域分三种
1: local 指当前作用域
通过locals() 能获取该命名空间的对象的dict
2:global 对应某个 .py 模块的作用域
通过globals() 能获取该命名空间的对象的dict
3:builtin 最顶层的作用域。
每次执行一个函数时, 就会创建新的局部命名空间。
解释器在检索变量的时候会按照 local》global 》builtin 的顺序检索。
比如检索变量 test(只要该变量没有被声明为local变量,=, -=, += 这样的操作会将变量声明为local变量)会先从 local 检索, 没有检索到则 检索 global, 再没检索到则检索 builtin. 如果最后没有检索到 则抛出 NameError的异常。
def space():
a = 21
print "local:", locals()
print "globals:", globals()
执行该函数的输出为:
local: {'a': 21}
globals: {'__builtins__': <module '__builtin__' (built-in)>, '__file__': 'space.py', '__package__': None, 'test': <function test at 0x7fe8e0535c08>, '__name__': '__main__', '__doc__': None}
这个栗子很好理解, 那么如果
a = 31
def space():
a = 21
print "local:", locals()
print "globals:", globals()
space()
的输出为:
local: {'a': 21}
globals: {'a': 31, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'space.py', '__package__': None, 'test': <function test at 0x7f7c0ec24c08>, '__name__': '__main__', '__doc__': None}
红色的能很方便我们理解 local 和global 作用域的区别。
在函数里面, 只要有 =, +=, -= 这样的赋值语句, 那么被赋值的变量就是local的
举个栗子:
def t(a): a += 1 print "a in function:", a print "locals:", locals() a = 21 t(a)
输出为:
a in function: 22
locals: {'a': 22}
a after invoking: 21
下面的代码也能正常进行
def t(): if a > 1: # 检索a会先从local作用域检索, 然后在检索global作用域, 发现a = 21 print "this a is global:", a print "a in function:", a print "locals:", locals() a = 21 t()
而下面的代码会报错:
def t(): if a > 1: print "this a is global:", a a = 3 # 此处因为有 +=, =, -= 这样的, 所以a在该函数t内是local的, 只会在local作用域检索a。然后上一句if a > 1会报错 print "a in function:", a print "locals:", locals() a = 21 t()
报错:
UnboundLocalError: local variable 'a' referenced before assignment
在函数里面,如果所传的值是容引用,那么在函数里面对容器的修改也会修改 global作用域内的该容器。
def t(a): a['hello'] = "happy" print "a in function:", a print "locals:", locals() a = {} t(a) print "a after invoking:", a
的输出为:
a in function: {'hello': 'happy'}
locals: {'a': {'hello': 'happy'}}
a after invoking: {'hello': 'happy'}
函数的参数默认值, test_default(下面栗子的)默认值为引用类型会在使用之后一直保存,每次对默认值的修改都会保留下来, 类似与C的静态局部变量。但是如果自己传了一个值来替换引用的默认值, 则不会修改保留下来的默认值。
def test_default(k, v, d = {}): d[k] = v print "d reference:", d test_default("k3", "v3", d = {}) #此处传了一个值来替换引用的默认值, 那么修改的不是默认引用的值 test_default("k1", "v1") test_default("k2", "v2")
的输出为:
d reference: {'k3': 'v3'}
d reference: {'k1': 'v1'}
d reference: {'k2': 'v2', 'k1': 'v1'}
lambda 里面的默认值
funcs = [lambda x, i=i: x*i for i in range(4)] print [func(2) for func in funcs]
的输出为:
[0, 2, 4, 6]
而:
funcs = [lambda x: x*i for i in range(4)] print [func(2) for func in funcs]
的输出为:
[6, 6, 6, 6]
函数在没有执行前, 内部代码不执行