python基础:名称空间与作用域
Python的变量定义后都有自己的作用域,每个作用域内都有名字空间。名称空间就是变量名称与对象的关联关系。Python中使用变量名引用对象,需要使用该变量时,就在命名空间中进行搜索,获取对应的对象。从目前python的实现上来讲,内部使用了字典,但是并不保证以后会更改实现,所以说现阶段,命名空间是一个字典(dictionary),它的键就是变量名,它的值就是那些变量的值。在一个Python程序运行中,至少有4个scopes是存在的。
直接访问一个变量可能在这四个namespace中逐一搜索。
- Local(innermost)
-
包含局部变量。
比如一个函数/方法内部。
- Enclosing
-
包含了非局部(non-local)也非全局(non-global)的变量。
比如两个嵌套函数,内层函数可能搜索外层函数的namespace,但该namespace对内层函数而言既非局部也非全局。
- Global(next-to-last)
-
当前脚本的最外层。
比如当前模块的全局变量。
- Built-in(outtermost)
-
Python
__builtin__模块。
包含了内建的变量/关键字等。
那么,这么多的作用域,Python是按什么顺序搜索对应作用域的呢?
著名的”LEGB-rule”,即scope的搜索顺序:
Local -> Enclosing -> Global -> Built-in
每个函数都有着自已的名称空间,叫做局部名称空间;
每个局部名称空间的外部的名称空间,叫做封闭区域;如内嵌函数的外部函数的局部名称空间,就是这个内嵌函数的封闭区域。
每个模块拥有它自已的名称空间,叫做全局名称空间;
还有就是内置名称空间,任何模块均可访问它,它存放着内置的函数和异常。
当有一个变量在 local 域中找不到时,Python会找上一层的作用域,即 enclosing 域(该域不一定存在)。
enclosing 域还找不到的时候,再往上一层,搜索模块内的 global 域。最后,会在 built-in 域中搜索。
对于最终没有搜索到时,Python会抛出一个 NameError 异常。
嵌套函数的情况:
1. 全局作用域有全局名字空间,在程序开始运行时生成,在程序退出时消失,可以通过globals()函数或dir("__main__")来访问全局名字空间。
2. 函数定义的函数体内就是局部名字空间,在调用函数时生成,在调用结束就消失,在函数体内调用locals()可以访问局部名字空间。Python中有一个现象非常奇特,在函数体内对全局变量进行赋值时需要使用global关键字进行变量声明,这是因为Python中有一个局部赋值规则造成的。比如说:
globalVar = 2
def myFunc():
globalVar = globalVar + 2
print globalVar
上述代码就会抛出“UnboundLocalError: local variable 'globalVar' referenced before assignment”的异常,要求变量必须先赋值。
如果在函数体内对变量进行赋值,python将名称添加到局部名字空间中,右侧执行运算时,发现在局部名字空间中有globalVar,就尝试将globalVar加1,而局部名字空间中的globalVar尚未赋值,就会抛出异常。
globalVar = 2
def myFunc():
global globalVar
globalVar = globalVar + 2
print globalVar
将globalVar声明为全局变量就会解决上述问题。
3. Encolsing Function变量的名字空间。简单的说就是在函数体内定义的新函数的本地名字空间。
globalVar = 2
def myFunc():
funVar = 3
def innerFunc():
innerVar = 4
innerVar2 = funVar
print 'inner locals:' + str(locals())
#print 'inner globals:' + str(globals()) innerFunc()
print 'outer locals:' + str(locals())
#print 'outer globals:' +str(globals())
此处略去了global函数的输出:
inner locals:{'funVar': 3, 'innerVar2': 3, 'innerVar': 4}
outer locals:{'funVar': 3, 'innerFunc': <function innerFunc at 0x0000000007BBC4A8>}
可以看出内部函数名是外部函数本地名字空间的一部分,内部函数在查找名字时会先查找本地名字空间,然后是外部函数的本地名字空间(封闭区域enclosing),再就是全局变量,最后是在内置模块名字空间中查找。
4. 内置模块的名字空间。python在启动时,会自动创建__builtins__模块,在该模块中定义了python数据类型。遵循LEGB搜索规则,如果Python不能在本地名字空间中找到某个名称,就会在全局命名空间中继续寻找,最后内置模块中查找。可以通过__builtins__.__dict__获取内置模块的名字。
最后补充Python使用面向对象编程中属性查找方法:
首先要知道:从某种意义上来说,一个对象(object)的所有属性(attribute)也构成了一个namespace.
a. 关于类类型和类实例对象的属性查找方法。比如以下的定义:
class MyBase(object):
pass
MyBase.attrA = 'foo'
MyBase.attrB = 'bar' baseObj = MyBase()
baseObj.attrA = 'hello'
baseObj.attrC = 'world' print baseObj.attrA # print hello
print baseObj.attrB # print bar print MyBase.attrC # AttributeError
如果在实例对象中找不到相关的属性就在类类型的名字空间中查找,但是反过来,在类类型中找不到的属性,不会向关联的实例对象名字空间中进行查找。这种情况也比较容易理解,毕竟类类型与类实例是一对多的关系。
这里另外有个微妙的地方需要强调。实例对象的属性一旦定义就会覆盖类类型名字空间中定义的属性。看下面的例子:
class Base(object):
var = 'hello' obj1 = Base()
obj1.var = 'world' obj2 = Base()
print 'obj1 value = ' + str(obj1.var) + '| id = ' + str(id(obj1.var))
print 'obj2 value = ' + str(obj2.var) + '| id = ' + str(id(obj2.var))
print 'Base value = ' + str(Base.var) + '| id = ' + str(id(Base.var))
执行结果:

b. 子类实例对象的属性如果在实例对象中查找不到,先在子类类型名字空间中查找,再向父类的名字空间中进行查找。
class PythonBase(object):
varBase = 'foo' class Derived(PythonBase):
pass derivedObj = Derived()
print derivedObj.varBase
python基础:名称空间与作用域的更多相关文章
- Python 的名称空间和作用域
最开始对名称空间的了解是在学习函数的时候,那时候知道了作用域的查找顺序,以及全局名称空间和局部名称空间,产生疑惑的时候为学递归的时候,那时候还没有名称空间这个概念,只知道递归有个最大深度,那时候以后递 ...
- 跟着太白老师学python day10 名称空间,作用域和取值顺序,变量的加载顺序
名称空间分为3种: 1. 全局名称空间 2. 内置名称空间 3. 局部名称空间(临时) 作用域 全局作用域 1全局名称空间 2 内置名称空间 局部作用域 ...
- Python基础—名称空间(Day10)
一.名称空间和作用域 1.全局名称空间(名称空间.命名空间): py文件运行时代码从上之下依次执行,看到一个变量就会将这个变量与对应值的内存地址的关系存到名称空间里,代码要运行时(print时)从名称 ...
- python函数名称空间与作用域、闭包
一.命名空间概念 1.命名空间(name space) 名称空间是存放名字的地方. 若变量x=1,1存放在内存中,命名空间是存放名字x.x与1绑定关系的地方. 2.名称空间加载顺序 python te ...
- python函数----名称空间和作用域
一 名称空间 名称空间即存放名字与对象映射/绑定关系的地方. 对于x=3,Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中,del x表示清除该绑定关系. 在程序执行 ...
- python基础知识13---函数对象、函数嵌套、名称空间与作用域、装饰器
阅读目录 一 函数对象 二 函数嵌套 三 名称空间与作用域 四 闭包函数 五 装饰器 六 练习题 一 函数对象 1 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 ...
- python基础之函数对象,嵌套,名称空间和作用域
函数对象: 函数是第一类对象的含义是函数可以被当作数据处理 函数可用于: def func(): print(‘func’) 1.引用 f = func 把内存地址赋值给f 2.当作参数传给一个函 ...
- Python 名称空间与作用域、闭包与装饰器
Python 的名称 Python 的名称(Name)是对象的一个标识(Identifier).我们知道,在 Python 里面一切皆对象,名称就是用来引用对象的.说得有点玄乎,我们以例子说明. 例如 ...
- python全栈开发-Day9 函数对象、函数嵌套、名称空间与作用域
一 .函数对象 一 .函数是第一类对象,即函数可以当作数据传递 可以被引用 可以当作参数传递 返回值可以是函数 可以当作容器类型的元素 二. 利用该特性,优雅的取代多分支的if def foo(): ...
- python第十二天, 三元表达式, 函数对象,名称空间与作用域,函数的嵌套定义
复习 1. 字符串的比较: 2. 函数的参数:形参与实参 3. 实参的分类:位置实参与关键字实参 4. 形参分类: 1.无值位置形参 2.有值位置形参 3.可变长位置形参 4.有无值关键字形参 5.可 ...
随机推荐
- Lowest Common Ancestor of a Binary Search Tree、Lowest Common Ancestor of a Binary Search Tree
1.Lowest Common Ancestor of a Binary Search Tree Total Accepted: 42225 Total Submissions: 111243 Dif ...
- c#datagrid的每行的单击事件
需要一个帮助类 using System; using System.Net; using System.Windows; using System.Windows.Controls; using S ...
- YII学习,初体验 ,对YII的一些理解.
先说点没用的: 不会选择,选择后不坚持,不断的选择.这是人生中的一个死循环,前两一直迷茫.觉得自己前进方向很不明朗.想去学的东西有很多.想学好YII,想学PYTHON 想学学hadoop什么的,又想研 ...
- PHP返回JSON和XML类
<?php class Reponse{ //private $result = array('code'=null,'message'=null,'data'=>null); /** * ...
- 测试框架mochajs详解
测试框架mochajs详解 章节目录 关于单元测试的想法 mocha单元测试框架简介 安装mocha 一个简单的例子 mocha支持的断言模块 同步代码测试 异步代码测试 promise代码测试 不建 ...
- python学习之day13
目录 JavaScript Dom jQuery JavaScript JavaScript 是世界上最流行的编程语言. 这门语言可用于 HTML 和 web,更可广泛用于服务器.PC.笔记本电脑 ...
- 一道C语言面试题:写一个宏,将16位的整数转为Big Endian
题目:输入16位整数x,如0x1234,将其转为Big Endian格式再输出,此例为输出 0x3412 来源:某500强企业面试题目 思路:将x左移8位得到a,将x右移8位得到b,a+b即为所得 / ...
- ubuntu 命令
用mount命令加载iso到虚拟光驱 先在/media/目录下新建一个空目录作为加载iso的虚拟光驱名称: sudo mkdir /media/aaaa 再用mount挂载: sudo mount - ...
- INSERT INTO blog_appitem (user_id,appid,app_secret,is_valid) VALUES (1, 'wxf415741de036114c','48e1e345fd5f11c93af18ff1714c7f78',1)
微信公众平台 INSERT INTO blog_appitem (user_id,appid,app_secret,is_valid) VALUES (1, 'wxf415741de036114c', ...
- 代码管理git总结
1. http://blog.csdn.net/teresa502/article/details/7388834 pwd 当前工作目录 cd(不加参数) 进root cd(folder) 进入文件夹 ...