python命名空间的本质

Python的命名空间是Python程序猿必须了解的内容,对Python命名空间的学习,将使我们在本质上掌握一些Python中的琐碎的规则。

接下来我将分四部分揭示Python命名空间的本质:一、命名空间的定义;二、命名空间的查找顺序;三、命名空间的生命周期;四、通过locals()和globals() BIF访问命名空间

重点是第四部分,我们将在此部分观察命名空间的内容。

一、命名空间

Python使用叫做命名空间的东西来记录变量的轨迹。命名空间是一个 字典(dictionary) ,它的键就是变量名,它的值就是那些变量的值。

namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries。

在一个 Python 程序中的任何一个地方,都存在几个可用的命名空间。

1、每个函数都有着自已的命名空间,叫做局部命名空间,它记录了函数的变量,包括函数的参数和局部定义的变量。

2、每个模块拥有它自已的命名空间,叫做全局命名空间,它记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。

3、还有就是内置命名空间,任何模块均可访问它,它存放着内置的函数和异常。

二、命名空间查找顺序

当一行代码要使用变量 x 的值时,Python 会到所有可用的名字空间去查找变量,按照如下顺序:

1、局部命名空间:特指当前函数或类的方法。如果函数定义了一个局部变量 x,或一个参数 x,Python 将使用它,然后停止搜索。

2、全局命名空间:特指当前的模块。如果模块定义了一个名为 x 的变量,函数或类,Python 将使用它然后停止搜索。

3、内置命名空间:对每个模块都是全局的。作为最后的尝试,Python 将假设 x 是内置函数或变量。

4、如果 Python 在这些名字空间找不到 x,它将放弃查找并引发一个 NameError 异常,如,NameError: name ‘aa‘ is not defined。

嵌套函数的情况:

1、先在当前 (嵌套的或 lambda) 函数的命名空间中搜索

2、然后是在父函数的命名空间中搜索

3、接着是模块命名空间中搜索

4、最后在内置命名空间中搜索

示例:

 1 info = "Adress : "
 2 def func_father(country):
 3     def func_son(area):
 4         city= "Shanghai " #此处的city变量,覆盖了父函数的city变量
 5         print(info + country + city + area)
 6     city = " Beijing "
 7     #调用内部函数
 8     func_son("ChaoYang ");
 9
10 func_father("China ")

输出:Adress : China Shanghai ChaoYang

以上示例中,info在全局命名空间中,country在父函数的命名空间中,city、area在自己函数的命名空间中

三、命名空间的生命周期

不同的命名空间在不同的时刻创建,有不同的生存期。

1、内置命名空间在 Python 解释器启动时创建,会一直保留,不被删除。

2、模块的全局命名空间在模块定义被读入时创建,通常模块命名空间也会一直保存到解释器退出。

3、当函数被调用时创建一个局部命名空间,当函数返回结果 或 抛出异常时,被删除。每一个递归调用的函数都拥有自己的命名空间。

  Python 的一个特别之处在于其赋值操作总是在最里层的作用域。赋值不会复制数据——只是将命名绑定到对象。删除也是如此:"del y" 只是从局部作用域的命名空间中删除命名 y 。事实上,所有引入新命名的操作都作用于局部作用域。

示例:

1 i=1
2 def func2():
3     i=i+1
4
5 func2();
6 #错误:UnboundLocalError: local variable ‘i‘ referenced before assignment

由于创建命名空间时,python会检查代码并填充局部命名空间。在python运行那行代码之前,就发现了对i的赋值,并把它添加到局部命名空间中。当函数执行时,python解释器认为i在局部命名空间中但没有值,所以会产生错误。

1 def func3():
2   y=123
3   del y
4   print(y)
5
6 func3()
7 #错误:UnboundLocalError: local variable ‘y‘ referenced before assignment
8 #去掉"del y"语句后,运行正常

四、命名空间的访问

1、局部命名空间可以 locals()  BIF来访问。

locals 返回一个名字/值对的 dictionary。这个 dictionary 的键是字符串形式的变量名字,dictionary 的值是变量的实际值。

示例:

1 def func1(i, str ):
2     x = 12345
3     print(locals())
4
5 func1(1 , "first")

输出:{‘str‘: ‘first‘, ‘x‘: 12345, ‘i‘: 1}

2、全局 (模块级别)命名空间可以通过 globals() BIF来访问。

示例:

 1 ‘‘‘Created on 2013-5-26‘‘‘
 2
 3 import copy
 4 from copy import deepcopy
 5
 6 gstr = "global string"
 7
 8 def func1(i, info):
 9     x = 12345
10     print(locals())
11
12 func1(1 , "first")
13
14 if __name__ == "__main__":
15     print("the current scope‘s global variables:")
16     dictionary=globals()
17     print(dictionary)

输出:(我自己给人为的换行、更换了顺序,加颜色的语句下面重点说明)

{

‘__name__‘: ‘__main__‘,

‘__doc__‘: ‘Created on 2013-5-26‘,

‘__package__‘: None,

‘__cached__‘: None,

‘__file__‘: ‘E:\\WorkspaceP\\Test1\\src\\base\\test1.py‘,

‘__loader__‘: <_frozen_importlib.SourceFileLoader object at 0x01C702D0>,

‘copy‘: <module ‘copy‘ from ‘D:\\Python33\\lib\\copy.py‘>,

‘__builtins__‘: <module ‘builtins‘ (built-in)>,

‘gstr‘: ‘global string‘,

‘dictionary‘: {...},

‘func1‘: <function func1 at 0x01C6C540>,

‘deepcopy‘: <function deepcopy at 0x01DB28A0>

}

总结

  1、模块的名字空间不仅仅包含模块级的变量和常量,还包括所有在模块中定义的函数和类。除此以外,它还包括了任何被导入到模块中的东西。

  2、我们看到,内置命名也同样被包含在一个模块中,它被称作 __builtin__。

  3、回想一下 from module import 和 import module 之间的不同。

    使用 import module,模块自身被导入,但是它保持着自已的名字空间,这就是为什么您需要使用模块名来访问它的函数或属性:module.function 的原因。

    但是使用 from module import function,实际上是从另一个模块中将指定的函数和属性导入到您自己的名字空间,这就是为什么您可以直接访问它们却不需要引用它们所来源的模块。使用 globals 函数,您会真切地看到这一切的发生,见上面的红色输出语句。

3、 locals 与 globals 之间的一个重要的区别

locals 是只读的,globals 不是

示例:

 1 def func1(i, info):
 2     x = 12345
 3     print(locals())
 4     locals()["x"]= 6789
 5     print("x=",x)
 6
 7 y=54321
 8 func1(1 , "first")
 9 globals()["y"]= 9876
10 print( "y=",y)

输出:

{‘i‘: 1, ‘x‘: 12345, ‘info‘: ‘first‘}

x= 12345

y= 9876

解释:

  locals 实际上没有返回局部名字空间,它返回的是一个拷贝。所以对它进行改变对局部名字空间中的变量值并无影响。

  globals 返回实际的全局名字空间,而不是一个拷贝。所以对 globals 所返回的 dictionary 的任何的改动都会直接影响到全局变量。

时间: 2024-08-30 07:52:14

python命名空间的本质的相关文章

python命名空间与作用域

python命名空间与作用域 命名空间是名称与对象之间的关系,可以将命名空间看做是字典,其中的键是名称,值是对象. 命名空间不共享名称. 在命名空间中的名称能将任何python对象作为值,在不同的命名空间中相同的名称可以与不同的对象相关联.但是,如果存在名称解析协议,则多个命名空间可以一起工作来解析名称.也就是说,如果有多个命名空间(总是有的),那么可以定义搜索的顺序,依次在不同的命名空间里来查找某个名称(或确认其不存在于任何认可的命名空间).在python中,将这一过程定义为作用域. 作用域搜

python命名空间与闭包函数详解

python命名空间与闭包函数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客主要介绍的知识点如下: 1>.三元运算 2>.命名空间 3>.global与nonlocal 4>.函数即变量 5>.嵌套函数 6>.闭包函数 一.三元运算 1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yi

[Python] 命名空间&amp;作用域

Python的类语句不会创建实例 类会创建命名空间,通过对象访问类的属性和方法 类不会创建作用域,对方法和属性的引用必须加以限定(如在方法中必须通过self引用实例的属性) class My1(): my1 = "My1bianliang" def __init__(self): print("My1gouzao") def __del__(self): print("My1xigou") class My2(): def __init__(se

Python - 命名空间和作用域

参考 https://blog.csdn.net/sakurainluojia/article/details/72783752 https://docs.python.org/3.6/tutorial/classes.html 概念 A scope is a textual region of a Python program where a namespace is directly accessible. "Directly accessible" here means that

初学python命名空间和LEGB原则

Python的命名空间是一个字典,字典内保存了变量名称与对象之间的映射关系,因此,查找变量名就是在命名空间字典中查找键-值对,想要打印出全局变量与局部变量的字典映射,我们可以使用函数globals()和locals().Python有多个命名空间,因此需要有规则来规定,LEGB就是用来规定命名空间查找顺序的规则,顺序为:local-->enclosing function locals-->global-->builtin. LEGB原则如下: 函数中变量命令空间易错点: 1.pytho

python decorator的本质

推荐查看博客:python的修饰器 对于Python的这个@注解语法糖- Syntactic Sugar 来说,当你在用某个@decorator来修饰某个函数func时,如下所示: @decorator def func(): pass 其解释器会解释成下面这样的语句: func = decorator(func) 是的,上面这句话在真实情况下执行了.如果我们执行以下代码: def fuck(fn): print "fuck %s!" % fn.__name__[::-1].upper

python命名空间和作用域

一.命名空间 定义:名称到对象的映射.命名空间是一个字典的实现,键为变量名,值是变量对应的值.各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响. 分类: 1.全局命名空间: 在代码一运行时就创建的命名空间. 2.局部命名空间: 指在程序运行过程中开辟的临时空间,比如函数,类 3.内置命名空间: 在程序运行加载代码前,提前开辟用于存储常用内置方法的空间,比如input,print,str,list,都属于内置命名空间的变量 加载顺序: 加载顺序:内置

Python之命名空间、闭包、装饰器

一.命名空间 1. 命名空间 命名空间是一个字典,key是变量名(包括函数.模块.变量等),value是变量的值. 2. 命名空间的种类和查找顺序 - 局部命名空间:当前函数 - 全局命名空间:当前模块 - 内建命名空间:所有Python环境,所有模块 查找顺序 1.先在当前 (嵌套的或 lambda) 函数的命名空间中搜索 2.然后是在父函数的命名空间中搜索 3.接着是模块命名空间中搜索 4.最后在内置命名空间中搜索 要到内置命名空间都没找到的话,就会弹出NameError 这里看一个例子 i

python的namespace的理解

Python命名空间的本质 python中的名称空间是名称(标识符)到对象的映射. 具体来说,python为模块.函数.类.对象保存一个字典(__dict__),里面就是重名称到对象的映射. ------------------------------------------------------------------------------------------- import urllib import re x=1 # 变量 def abc(): # 函数 pass def qq(s