在本文中,您将了解命名空间,从名称到对象的映射以及变量的作用域。
如果您曾经读过“ Python之禅(The Zen of Python) ”(在Python解释器中输入import this),最后一行指出,命名空间是一个很棒的主意-让我们做更多的事情!那么这些神秘的命名空间是什么?首先让我们看看名称是什么。
名称(也称为标识符)只是赋予对象的名称。Python中的一切都是。名称是访问基础对象的一种方式。
例如,当我们执行赋值操作时a = 2,2是一个存储在内存中的对象,而a是与之关联的名称。我们可以通过内置函数 获取某些对象的地址(在RAM中)id()。让我们看看如何使用它。
# 注意:您可能会得到不同的id值 a = 2 print('id(2) =', id(2)) print('id(a) =', id(a))
输出结果
id(2) = 9302208 id(a) = 9302208
在这里,两者都引用相同的对象2,因此它们具有相同的id()。让我们做些有趣的事情。
# 注意:您可能会得到不同的id值 a = 2 print('id(a) =', id(a)) a = a+1 print('id(a) =', id(a)) print('id(3) =', id(3)) b = 2 print('id(b) =', id(b)) print('id(2) =', id(2))
输出结果
id(a) = 9302208 id(a) = 9302240 id(3) = 9302240 id(b) = 9302208 id(2) = 9302208
上述步骤序列中发生了什么?让我们用一个图来解释一下:
最初,创建一个对象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 a()
输出结果
Hello
相同的名称a可以引用一个函数,我们可以使用该名称来调用该函数。
现在我们了解了名称是什么,我们可以继续进行命名空间的概念。
简而言之,命名空间是名称的集合。
在Python中,您可以将命名空间想象为已定义的每个名称到对应对象的映射。
不同的命名空间可以在给定时间共存,但完全隔离。
当我们启动Python解释器时,将创建一个包含所有内置名称的命名空间,并且只要该解释器运行,该命名空间就会存在。
这就是为什么内置的功能(例如id())print()等始终可以从程序的任何部分使用的原因。每个创建自己的全局命名空间。
这些不同的命名空间是隔离的。因此,不同模块中可能存在的相同名称不会冲突。
模块可以具有各种功能和类。调用函数时会创建一个本地命名空间,其中定义了所有名称。与类相似。下图可能有助于阐明这一概念。
尽管定义了各种唯一的命名空间,但我们可能无法从程序的每个部分访问它们。作用域的概念开始起作用。
作用域是程序的一部分,从那里可以直接访问命名空间而无需任何前缀。
在任何给定时刻,至少有三个嵌套作用域。
具有本地名称的当前函数的作用域
具有全局名称的模块的作用域
具有内置名称的最外部作用域
在函数内部进行引用时,将在本地命名空间中搜索名称,然后在全局命名空间中搜索,最后在内置命名空间中搜索。
如果另一个函数内有一个函数,则新作用域嵌套在本地作用域内。
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读取和分配新值,但只能 从中读取b和ainner_function()。
如果我们尝试分配作为值b,一个新的变量b在本地命名空间比非本地不同的创建b。当我们分配一个值,同样的事情发生一个。
但是,如果我们将a声明为全局a,则所有引用和赋值都将移至全局a。同样,如果我们想重新绑定变量b,则必须将其声明为非本地变量。以下示例将进一步阐明这一点。
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 = 30 a = 20 a = 10
在此程序中,在不同的命名空间中定义了三个不同的变量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)
程序的输出是。
a = 30 a = 30 a = 30
在这里,由于使用了关键字global,所以所有引用和赋值都指向全局a。