好好学习,天天向上,今天是:2017.05.19
</br>
Python命名空间、作用域一直没看懂。
这篇文是网上看到的,写的很好。
动手再梳理了下,然后再 将内容全部手打了一遍,增加理解。
原文:Python命名空间的本质 - windlaughing - 博客园 (http://www.cnblogs.com/windlaughing/archive/2013/05/26/3100362.html )
</br>
思维导图
</br>
</br>
1、定义
Namespace是名字到对象的一个映射。绝大部分是dict形式,它的见健是那些变量值,值是那些变量的值。
A namespaceis a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries。
从某种那意义上来说,一个对象(object)的所有属性(attribute)也构成了一个namespace。在程序执行之间,会有不同的namespace同时存在。对于不同的命名空间内,相同名字的两个变量,这两个变量没有任何关系(互不影响)。
Python程序中,存在几个可用的命名空间:
局部命名空间:函数的命名空间,记录函数的变量,包括函数的参数和局部定义的变量
全局命名空间:模块的命名空间,记录模块的变量,包括函数、类、其它导入的模块、模块级变量和常量
内置命名空间:任何模块皆可访问,放置着内部函数和异常
</br>
</br>
2、查找顺序
一行代码要使用一个变量的名字时,会从所有命名空间去寻找,查找顺序如下:
1)一般情况
局部命名空间,全局命名空间,内置命名空间,若在这些命名空间找不到相关变量,Python会放弃查找并且引发一个NameError异常
2)嵌套函数
现在当前函数(嵌套或者lambda)的命名空间中查找,然后再父类函数命名空间中查找,接着在模块命名空间中查找,最后在内置命名空间中查找。
实例:
info="Adress:"
def func_father(country):
def func_son(area):
city="Chengdu"
print (info+country+city+area)
city="Beijing" # 此处的city变量,覆盖了父类的city变量
#调用内部函数
func_son("Wuhouqu")
func_father("China")
输出:
Adress:China Chengdu Wuhouqu
以上实例中,info在全局命名空间中,country在父类函数的命名空间中,city、area在自己函数的命名空间中
</br>
</br>
3、生命周期
不同Namespace的创建\销毁时间不同,就是说有不一样的生命周期。
1)内置命名空间在Python解释器启动时自动创建,会一直保留,不会删除
2)模块的全局命名空间在模块定义被读入时创建,通常一直保存到解释器退出
3)局部命名空间在函数被调用时创建,返回结果或抛出异常时被删除。所有递归调用的函数都有自己的命名空间
Python的一个特别之处是:
a、如果没有global关键字变量声明,一个变量的赋值总在最里层的作用域(innermost)
b、赋值不会复制数据,只是将命名绑定到对象。删除也是如此,"del y"只是从局部命名空间里删除命名y。(事实上,所有引入新命名的操作都作用于局部作用域)
c、赋值语句通常会隐式创建一个局部变量,即便在上一层作用域中已经存在该变量的赋值语句
实例1:
i=2
def func2():
i=i+1
func2()
#错误:UnbondLocalError:local variable 'i' referenced before assignment
由上,Python解释器执行到func3函数时,因为没有在局部作用域中找到对i的赋值(i=i+1无效),所以会抛出一个错误(原文:Python在检查代码前,发现了对i的赋值,并将其添加至局部命名空间中。执行时Python解释器会认为i在局部命名空间中但是没有值,所以产生错误)
def func3():
y=123
del y
print y
func3()
#错误:UnbondLocalError:local variable 'y' referenced before assignment
#取掉del y后运行正常
</br>
</br>
4、命名空间访问
1)局部命名空间可以用locals() BIF访问
locals()返回一个键/值的dict,键为变量名字(str形式),值为该变量的实际值
实例:
def func1(i,str):
x=12345
print (locals())
func1(1,'first')
输出:
{'str':'first','x':'12345','i':'1'}
2)全局(模块级别)命名空间可以用globals()BIF访问
实例:
'''Created on 2013-5-26'''
import copy
from copy import deepcopy
gstr = "global string"
def func1(i, info):
x = 12345
print(locals())
func1(1 , "first")
if __name__ == "__main__":
print("the current scope's global variables:")
dictionary=globals()
print(dictionary)
输出:
注意:
a、模块的命名空间不仅包括模块的常量和变量,还包括模块中定义的函数和类。此外还包括,任何被导入模块中的东西。
b、内置命名同样放置在一个模块中,被称作builtins
c、from module import 和import module不同:
使用import module,模块被导入,但是它仍保持自己的命名空间,所以需要模块名来访问函数或者属性(例如module.function);使用from module import function ,实际上是直接从另一个模块中导入相关属性或函数,因此可以直接访问而不需要知道它们的来源。使用globals函数可以实现。
3)locals()和globals()区别
locals是只读的(不能改变),globals不是(可以改变)
实例:
def func1(i,info):
x=12345
print locals()
locals()['x']='6789'
print 'x=',x
y=54321
func1('1','first')
globals()['y']='9876'
print 'y=',y
输出:
{‘info’:'first','x':'12345','i':'1'}
x=12345
y=9876
注意:
a、locals没有返回局部命名空间,它返回的是一个拷贝。所以对它进行改变,对局部命名空间中的变量值没有影响
b、globals返回全部实际命名空间,而非拷贝。所以globals返回的dict任何改动都会影响到全局变量(本例中后面的y覆盖掉了前面的y)
作用域、拷贝之类还没看,后面这一个有一些不太理解,先大概这样。
网友评论