前言:
如果你接触过c/c++/c#/java,那么对于python中的命名空间也是如此,只不过在些许地方存在细微差异,不过倒无伤大雅。
1. 定义
命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 python 字典来实现的。
命名空间提供了在项目中避免名字冲突的一种方法
。各个命名空间之间相互独立,没有任何关系
。同一个命名空间中不能有重名的,但不同的命名空间是可以重名而没有任何影响
。
实际上命名空间和操作系统中的文件系统的思想是类似的,分而治之
。就比如说,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名
。
Notice:同一个命名空间中不能有重名的,该怎么理解???
# 我们在全局的命名空间中定义了变量num, 变量赋值num=1后再赋值num=2,
# 这里实际是新生成一个int值对象2, 再让num指向它,而1被丢弃, 不是改变a的值, 相当于新生成了num.
# 我们通过id()就可以清晰的看出, 两次num的id值确实不同.
# 先num=1, 再num=2的行为在c/c++中就是变量重定义的行为, 是万万不行的, 但是在python中, 却是合理的.
# 可以这么理解, num一开始指向存储对象1的那块内存空间, 后来它有指向了对象2所指代的那块内存空间.
num =1
print(id(num))
num =2
print(id(num))
print(num)
print('-----------------------')
def test():
print('Hello')
print(id(test))
def test():
print('world')
print(id(test))
test()
[Question]
:那这样一来,同一个命名空间中不能有重名的这句话究竟该怎么去理解它,我表示怀疑,此处目前留待查证,后续给出相关解释
。
2. 有什么好处
现在的软件项目都是一个团队协作,共同开发,每个人开发不同的功能,生成不同的python模块。因此,很容易出现同名的变量、函数或者类定义。那么有了命名空间,这个问题很容易就解决了。因为,不同的模块有不同的命名空间,命名空间之间是相互独立的。
3. 三种命名空间
python中存在3中命名空间。
3.1
内置命名空间(built-in names)
python 语言内置的名称
,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
(1)
python 解释器内置了很多函数, 不需要使用 import 导入即可使用。
# python 程序可以直接使用内置函数max()和abs().
print(max(1,12))
print(abs(-2))
(2)
python 提供了一个内置命名空间,用于记录这些内置函数。python 中存在一个特殊的 builtins 模块
,它记录了所有的内置函数。
import builtins
print(dir(builtins)) # dir()列出builtins模块中的变量和函数的名称
3.2
全局命名空间(global names)
模块中定义的名称
,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
(1)
python 中的内置函数 globals()
返回表示全局命名空间的字典。
# 在全局空间定义类Studnet, 函数test(), 变量s1和s2
class Student:
def __init__(self, num):
self.num = num
def show(self):
pass
def test():
pass
s1 = Student(101)
s2 = Student(102)
print(globals())
# 程序输出
# 输出包括了 Student、test、s1和s2, 它们是用户定义的全局函数和变量.
{
'__name__': '__main__',
'__doc__': None,
'__package__': None,
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001ADFF046D00>,
'__spec__': None,
'__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>,
'__file__': 'F:\\编程系列\\Python\\Python\\_01_Essential\\temp.py',
'__cached__': None,
'Student': <class '__main__.Student'>,
'test': <function test at 0x000001ADFF1DA550>,
's1': <__main__.Student object at 0x000001ADFF1E2FD0>,
's2': <__main__.Student object at 0x000001ADFF1E2F10>
}
3.3
局部命名空间(local names)
函数中定义的名称
,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
(1)
python 中的内置函数 locals()
返回表示全局命名空间的字典。
# Student类的构造函数中定义两个参数num, name, 以及在test()中定义一个局部变量addr.
# test()中定义2个参数num1, num2, 以及局部变量temp.
# 输出了函数参数和函数中定义的局部变量.
# Notice:locals()不能在全局中打印, 否则无法打印出以下效果.
class Student:
def __init__(self, num, name):
self.num = num
self.name = name
print(locals())
def test(self):
addr = 'SuZhou'
print(locals())
def test(num1, num2):
temp = 2
print(locals())
return num1 + num2 + temp
test(1, 3)
print('------')
Student(101, 'Zhang').test()
4. 命名空间的查找顺序
假设我们要使用变量 temp,则 python 的查找顺序为:局部的命名空间 -> 全局命名空间 -> 内置命名空间
。
如果找不到变量 temp,它将放弃查找并引发一个 NameError 异常。
(1)
在局部命名空间中,查找变量;
(2)
如果找不到,则在全局命名空间中,查找变量;
(3)
如果找不到,则在内置命名空间中,查找变量;
(4)
如果找不到,则抛出 NameError 异常。
# 示例性代码
tel = 101
name = 'Zhang'
def test(num1, num2):
temp1 = 12
temp2 = 24
# 在此处访问某个变量
'''
内置命名空间, 包括: max、min、abs 等内置函数
全局命名空间, 包括:tel, name, test()
局部命名空间, 包括:num1, num2, temp1, temp2
'''
'''
如果访问的变量是num1, 则能在局部命名空间中找到;
如果访问的变量是tel, 则能在全局命名空间中找到;
如果访问的变量是max,则能在内置命名空间中找到;
如果访问的变量是 x,在以上三个命名空间中查找不到, 此时抛出异常 NameError.
'''
test()
5. 命名空间的生命周期
命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。