上一章Python教程请查看:python3操作符
在本文中你将了解python的名称空间,从名称到对象和变量作用域的映射。
Python中的名称是什么?
如果你曾经读过“Zen
of Python”(在Python解释器中输入“import
this”),最后一行说明名称空间是一个伟大的想法——让我们做更多这样的事情!那么这些神秘的名称空间是什么呢?让我们先看看名称是什么。
名称(也称为标识符)就是给对象的一个名称,Python中的一切都是对象,名称是访问底层对象的一种方式。
例如,当我们执行赋值a
= 2时,这里2是存储在内存中的对象,而a是与之关联的名称。我们可以通过内建函数id()获得某个对象的地址(在RAM中),我们检查一下。
# 注意: 可能会得到不同的id值
a = 2
# 输出: id(2)= 1403308176
print('id(2) =', id(2))
# 输出: id(a) = 1403308176
print('id(a) =', id(a))
在这里,两者都指向同一个对象,我们把事情变得更有趣一点。
# 注意: 可能会得到不同的id值
a = 2
# 输出: id(a) = 1403308176
print('id(a) =', id(a))
a = a+1
# 输出: id(a) = 1403308192
print('id(a) =', id(a))
# 输出: id(3) = 1403308192
print('id(3) =', id(3))
b = 2
# 输出: id(2)= 1403308176
print('id(2) =', id(2))
在上述步骤中发生了什么?图表可以帮助我们解释这一点。
最初,创建一个对象2并将名称a与之关联,当我们执行a = a+1时,将创建一个新对象3,现在a与此对象关联。
注意,id(a)和id(3)具有相同的值。
此外,当我们执行b =
2时,新名称b将与前一个对象2相关联。
这是非常有效的,因为Python不需要创建一个新的复制对象。名称绑定的这种动态特性使Python功能强大,名称可以引用任何类型的对象。
>>> a = 5
>>> a = 'Hello World!'
>>> a = [1,2,3]
所有这些都是有效的,a将在不同的实例中引用三种不同类型的对象。函数也是对象,所以名称也可以引用它们。
def printHello():
print("Hello")
a = printHello()
# 输出: Hello
a
我们的名称a可以指一个函数,这样我们可以通过它来调用这个函数。
Python中的名称空间是什么?
既然我们已经了解了名称是什么,那么我们就可以继续讨论名称空间的概念了。
简单地说,namespace名称空间是名称的集合。
在Python中,可以将名称空间想象成已定义的每个名称到对应对象的映射。
不同的名称空间可以同时存在,但是完全隔离。
在启动Python解释器时,将创建一个包含所有内置名称的名称空间,只要不退出就会一直存在。
这就是为什么像id()、print()等内置函数总是可以从程序的任何部分获得的原因,每个模块都创建自己的全局名称空间。
这些不同的名称空间是独立的,因此,可能存在于不同模块中的相同名称不会发生冲突。
模块可以有各种函数和类,调用一个函数时会创建一个本地名称空间,其中定义了所有的名称。类也是类似的情况,下面的图表可能有助于阐明这个概念。
Python变量作用域
尽管定义了各种独特的名称空间,但我们可能无法从程序的每个部分访问所有名称空间,因而作用域的概念开始发挥作用。
作用域是程序的一部分,从这里可以直接访问名称空间,而不需要任何前缀。
在任何给定时刻,至少有三个嵌套作用域。
具有本地名称的当前函数的作用域
具有全局名称的模块的作用域
具有内置名称的最外层作用域
当在函数内部创建引用时,将在本地名称空间中搜索该名称,然后在全局名称空间中搜索,最后在内置名称空间中搜索。
如果在另一个函数中有一个函数,则在局部作用域内嵌套一个新作用域。
Python中作用域和命名空间的例子
def outer_function():
b = 20
def inner_func():
c = 30
a = 10
这里,变量a位于全局名称空间中。变量b位于outer_function()的本地名称空间中,而c位于inner_function()的嵌套本地名称空间中。
在inner_function()中,c是局部的,b是非局部的,a是全局的。我们可以读取并将新值赋给c,但只能从inner_function()中读取b和a。
如果我们试图将一个值赋给b,就会在本地名称空间中创建一个新的变量b,它与非本地的b不同。
但是,如果我们将a声明为全局变量,那么所有的引用和赋值都将指向全局变量a。下面的示例将进一步阐明这一点
def outer_function():
a = 20
def inner_function():
a = 30
print('a =',a)
inner_function()
print('a =',a)
a = 10
outer_function()
print('a =',a)
在这个程序中,在单独的名称空间中定义了三个不同的变量a,并相应地进行访问。而在接下来的程序中:
def outer_function():
global a
a = 20
def inner_function():
global a
a = 30
print('a =',a)
inner_function()
print('a =',a)
a = 10
outer_function()
print('a =',a)
在这里,由于使用了关键字global,所有引用和赋值都指向全局变量a。