函数内部的作用域:
def a():
def b():
c = "c"
c = "d"
b()
print(c)
a()
执行结果:
d
可以看到,虽然执行了b()函数,但c的值并没有发生变化,这就引入了命名空间这个定义。
官方文档是这么定义的:
namespace (命名空间)是一个从名字到对象的映射。 大部分命名空间当前都由 Python 字典实现,但一般情况下基本不会去关注它们(除了要面对性能问题时),而且也有可能在将来更改。 下面是几个命名空间的例子:存放内置函数的集合(包含 abs() 这样的函数,和内建的异常等);模块中的全局名称;函数调用中的局部名称。 从某种意义上说,对象的属性集合也是一种命名空间的形式。 关于命名空间的重要一点是,不同命名空间中的名称之间绝对没有关系;例如,两个不同的模块都可以定义一个 maximize 函数而不会产生混淆 — 模块的用户必须在其前面加上模块名称。
简单来说就是三个:
1、python的内置函数
2、全局变量
3、局部变量
可以用一段代码测试一下:
abs = "全局命名空间"
def test():
abs = "局部命名空间"
print("局部测试", abs)
test()
print("全局测试", abs)
del abs
print("内置测试", abs)
结果:
可以看到函数内部的print打印的是“局部命名空间”,第二个print打印的是“全局命名空间”,然后最后一个是打印的python对象。也就是说python查找的命名空间的顺序是局部空间–全局空间–内置函数在函数内部的时候找到了abs这个变量,座椅就不再继续向下一个寻找,我们可以测试一下:
abs = "全局命名空间"
def test():
# abs = "局部命名空间"
print("局部测试", abs)
test()
print("全局测试", abs)
del abs
print("内置测试", abs)
结果:
可以可看到我注释了函数内部的abs,所以他自己去全局寻找了,然后等我们把abs删除后,python会去内置函数里寻找,如果内置函数没有,就会引发异常:NameError: name xxx is not defined
那可能到这儿就有疑问了,既然最先从局部空间找,为什么第二个print打印的不是test函数里的abs呢,这就引入了命名空间的生存周期:
命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。 因此,我们无法从外部命名空间访问内部命名空间的对象
。
原文来自菜鸟教程