Python 命名空间和范围
Python 命名空间和作用域
在本教程中,您将了解命名空间、从名称到对象的映射以及变量的范围。
Python 中的名称是什么?
如果你读过《Python 之禅》(类型 import this
在 Python 解释器中),最后一行指出,命名空间是一个很棒的主意——让我们做更多的事情! 那么这些神秘的命名空间是什么?我们先来看看叫什么名字。
名称(也称为标识符)只是赋予对象的名称。 Python 中的一切都是对象。名称是访问底层对象的一种方式。
例如,当我们进行赋值 a = 2
, 2
是存储在内存中的对象,a 是我们与之关联的名称。我们可以通过内置函数 id()
获取某个对象的地址(在 RAM 中) .让我们看看如何使用它。
# Note: You may get different values for the id
a = 2
print('id(2) =', id(2))
print('id(a) =', id(a))
输出
id(2) = 9302208 id(a) = 9302208
在这里,两者都引用同一个对象 2
,所以它们有相同的 id()
.让我们让事情变得更有趣。
# Note: You may get different values for the 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 中,您可以将命名空间想象为您定义的每个名称到相应对象的映射。
不同的命名空间可以在给定时间共存,但完全隔离。
当我们启动 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 分配新值 但只能读取 b 和 a 来自 inner_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
在这里,所有的引用和赋值都指向全局 a 由于使用了关键字global
.
Python