源自 我的博客
       python 里面最核心的内容就是:名字空间(namespace)    
例1
#!/usr/bin/env python # encoding: utf-8   def func1():     x = 1     print globals()     print 'before func1:', locals()      def func2():         a = 1         print 'before fun2:', locals()         a += x         print 'after fun2:', locals()      func2()     print 'after func1:', locals()     print globals()  if __name__ == '__main__':     func1() 可以正常输出结果: 并且需要注意,在    func2 使用    x 变量之前的名字空间就已经有了    'x':1 .  
before func1: {'x': 1} before fun2: {'a': 1, 'x': 1} after fun2: {'a': 2, 'x': 1} after func1: {'x': 1, 'func2': <function func2 at 0x7f7c89700b90>}稍微改一点:如下
例2:
#!/usr/bin/env python # encoding: utf-8   def func1():     x = 1     print 'before func1:', locals()      def func2():         print 'before fun2:', locals()         x += x #就是这里使用x其余地方不变         print 'after fun2:', locals()      func2()     print 'after func1:', locals()  if __name__ == '__main__':     func1() 输出就开始报错: 而且在    before func2 也没有了    x .  
before func1: {'x': 1} before fun2: {} Traceback (most recent call last):   File "test.py", line 18, in <module>     func1()   File "test.py", line 14, in func1     func2()   File "test.py", line 11, in func2     x += x UnboundLocalError: local variable 'x' referenced before assignment  这两个例子正好涉及到了    python 里面最核心的内容:    名字空间 ,正好总结一下,然后在解释这几个例子。  
比如我们定义一个"变量"
In [14]: a NameError: name 'a' is not defined 所以,这里更准确的叫法应该是    名字 。 一些语言中比如    c,c++,java 变量名是内存地址别名, 而Python 的名字就是一个字符串,它与所指向的目标对象关联构成名字空间里面的一个键值对    {name: object} ,因此可以这么说,python的    名字空间 就是一个字典.。  
 python里面有很多名字空间,每个地方都有自己的名字空间,互不干扰,不同空间中的两个相同名字的变量之间没有任何联系一般有4种:    LEGB 四种  
         locals : 函数内部的名字空间,一般包括函数的局部变量以及形式参数      
         enclosiing function : 在嵌套函数中外部函数的名字空间, 对        fun2 来说,        fun1 的名字空间就是。      
         globals : 当前的模块空间,模块就是一些        py 文件。也就是说,globals()类似全局变量。      
         __builtins__ : 内置模块空间, 也就是内置变量或者内置函数的名字空间。      
 当程序引用某个变量的名字时,就会从当前名字空间开始搜索。搜索顺序规则便是:    LEGB .  
locals  -> enclosing function -> globals -> __builtins 一层一层的查找,找到了之后,便停止搜索,如果最后没有找到,则抛出在      NameError 的异常。这里暂时先不讨论      赋值 操作。    
 比如例1中的      a = x + 1 这行代码,需要引用      x , 则按照      LEGB 的顺序查找,locals()也就是      func2 的名字空间没有,进而开始      E ,也就是      func1 ,里面有,找到了,停止搜索,还有后续工作,就是把      x 也加到自己的名字空间,这也是为什么      fun2 的名字空间里面也有      x 的原因。    
其实上面都已经说了,这里暂时简单列一下
 使用        locals() 访问局部命名空间      
 使用          globals() 访问全局命名空间        
 这里有一点需要注意,就是涉及到了          from A import B 和          import A 的一点区别。        
#!/usr/bin/env python # encoding: utf-8  import copy from copy import deepcopy   def func():     x = 123     print 'func locals:',locals()  s = 'hello world' if __name__ == '__main__':     func()     print 'globals:', globals()输出结果:
func locals: {'x': 123} globals: {'__builtins__': <module '__builtin__' (built-in)>,  '__file__': 'test.py',  '__package__': None,  's': 'hello world', 'func': <function func at 0x7f1c3d617c80>,  'deepcopy': <function deepcopy at 0x7f1c3d6177d0>,  '__name__': '__main__',  'copy': <module 'copy' from '/usr/lib/python2.7/copy.pyc'>,  '__doc__': None} 从输出结果可以看出    globals() 包含了定义的函数,变量等。对于    'deepcopy': <function deepcopy at 0x7f1c3d6177d0> 可以看出    deepcopy 已经被导入到自己的名字空间了,而不是在    copy 里面。 而导入的    import copy 则还保留着自身的名字空间。因此要访问    copy 的方法,就需要使用    copy.function 了。这也就是为什么推荐使用    import module 的原因,因为    from A import B 这样会把    B 引入自身的名字空间,容易发生覆盖或者说污染。  
每个名字空间都有自己的生存周期,如下:
         __builtins__ : 在        python 解释器启动的时候,便已经创建,直到退出      
         globals : 在模块定义被读入时创建,通常也一直保存到解释器退出。      
         locals : 在        函数调用 时创建, 直到函数返回,或者抛出异常之后,销毁。 另外递归函数每一次均有自己的名字空间。      
 看着没有问题,但是有很多地方需要考虑。比如名字空间都是在代码编译时期确定的,而不是执行期间。这个也就可以解释为什么在例1中,    before func2: 的locals()里面包含了    x: 1 这一项。再看下面这个,  
def func():     if False:         x = 10 #该语句永远不执行     print x肯定会报错的,但是错误不是
NameError: global name 'x' is not defined而是:
UnboundLocalError: local variable 'x' referenced before assignment 虽然    x = 10 永远不会执行,但是在执行之前的编译阶段,就会把    x 作为    locals 变量,但是后面编译到    print 的时候,发现没有赋值,因此直接抛出异常,    locals() 里面便不会有    x 。这个就跟例子2中,    before func2 里面没有    x 是一个道理。  
为什么要把赋值单独列出来呢,因为赋值操作对名字空间的影响很大,而且很多地方需要注意。
核心就是: 赋值修改的是命名空间,而不是对象 , 比如:
a = 10 这个语句就是把    a 放入到了对应的命名空间, 然后让它指向一个值为10的整数对象。  
a = [] a.append(1)  这个就是把      a 放入到名字空间,然后指向一个列表对象, 然而后面的      a.append(1) 这句话只是修改了      list 的内容,并没有修改它的内存地址。因此    
并没有涉及到修改名字空间。
赋值操作有个特点就是: 赋值操作总是在最里层的作用域.也就说,只要编译到了有赋值操作,就会在当前名字空间内新创建一个名字,然后开始才绑定对象。即便该名字已存在于赋值语句发生的上一层作用域中;
 现在再看例子2, 就清晰多了,    x += x 编译到这里时,发现了赋值语句,于是准备把    x 新加入最内层名字空间也就是    func2 中,即使上层函数已经存在了; 但是赋值的时候,又要用到    x 的值, 然后就会报错:  
UnboundLocalError: local variable 'x' referenced before assignment 这样看起来好像就是 内部函数只可以读取外部函数的变量,而不能做修改,其实本质还是因为      赋值 涉及到了新建      locals() 的名字。    
在稍微改一点:
#!/usr/bin/env python # encoding: utf-8  def func1():     x = [1,2]     print 'before func1:', locals()      def func2():         print 'before fun2:', locals()         x[0] += x[0] #就是这里使用x[0]其余地方不变         print 'after fun2:', locals()      func2()     print 'after func1:', locals()  if __name__ == '__main__':     func1() 这个结果就是:
 before func1: {'x': [1, 2]} before fun2: {'x': [1, 2]} after fun2: {'x': [2, 2]} after func1: {'x': [2, 2], 'func2': <function func2 at 0x7fb67b253b18>}  咋正确了呢---这不应该要报错吗? 其实不然,就跟上面的      a.append(1) 是一个道理。    
       x[0] += x[0] 这个并不是对      x 的赋值操作。按照      LEGB 原则, 搜到      func1 有变量      x 并且是个      list , 然后将其加入到自己的      locals() , 后面的      x[0] += x[0] , 就开始读取      x 的元素,并没有影响      func2 的名字空间。另外无论      func1 与      func2 的名字空间的      x 没有什么关系,只不过都是对      [1, 2] 这个列表对象的一个引用。    
 这个例子其实也给了我们一个启发,我们知道内部函数无法直接修改外部函数的变量值,如例2,如果借助      list 的话, 就可以了吧!比如把想要修改的变量塞到一个      list 里面,然后在内部函数里面做改变!当然      python3.x 里面有了      nonlocal 关键字,直接声明一下就可以修改了。看到这里,对作用域理解应该有一点点了吧。    
 我们都知道闭包是把外部函数的值放到      func.func_closure 里面,为什么不像上面的例子一样直接放到函数的名字空间呢?    
 这是因为      locals() 空间是在函数调用的时候才创建! 而闭包只是返回了一个函数, 并没有调用,也就没有所谓的空间。    
 在最外层的模块空间里    locals() 就是    globals()   
In [2]: locals() is globals() Out[2]: True 另外我们可以手动修改    globals() 来创建名字  
In [3]: globals()['a'] = 'abcde' In [4]: a Out[4]: 'abcde' 但是    locals() 在函数里面的话, 貌似是不起作用的,如下:  
In [5]: def func():    ...:     x = 10    ...:     print x    ...:     print locals()    ...:     locals()['x'] = 20    ...:     print x In [6]: func() 10 {'x': 10} 10  这是因为解释器会将 locals 名字复制到 一个叫    FAST 的 区域来优化访问速度,而实际上解释器访问对象时,是从    FAST 区域里面读取的,而非    locals() 。所以直接修改    locals() 并不能影响    x (可以使用    exec 动态访问,不再细述)。 不过赋值操作,会同时刷新    locals() 和    FAST 区域。  
 查了不少资料,说了这么多,我只想说,作为    python 最核心的东西,名字空间还有很多很多地方需要探究,比如  
作用域(scope)与名字空间, 这里只是模糊了二者的区别
面向对象,也就是类的名字空间, 又有不一样的地方。。。
学一点记录一点吧。
1
2
3