深入理解Python if...else语句与运算符:探索命名空间、对象映射及变量作用域
Python if...else 语句Python 运算符

Python 命名空间和作用域
在本文里,您会知晓命名空间。您会知晓从名称到对象的映射。您会知晓变量的作用域。
Python中的命名空间是什么?
如果您读过“Python 之禅(The Zen of Python)”(在 Python 解释器中输入 import this),其中最后一行表明,命名空间是个很棒的主意,让我们去做更多的事情!那么,这些神秘的命名空间究竟是什么呢?首先,让我们来看一下名称是什么。
名称是赋予对象的称呼。对象有了名称后就有了标识。在 Python 中,一切事物都可视为对象。而名称能够作为一种途径去访问那些基础的对象。
当执行赋值操作时,比如 a = 2 。2 是存储在内存里的一个对象,a 是与之相关联的名称。我们能够通过内置函数 id()来获取某些对象在内存(RAM 中)的地址。接下来让我们看看该如何使用它。
# 注意:您可能会得到不同的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
上述步骤序列中发生了什么?让我们用一个图来解释一下:
Python中变量的内存图
首先创建一个对象 2 并把名称 a 与它关联起来。接着当执行 a = a + 1 这个操作时,就会创建出一个新的对象 3 。此时 a 与这个新创建的对象 3 相关联。
请注意,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变量作用域
虽然定义了各种独一无二的命名空间,但是我们或许无法从程序的每一个部分去访问它们。此时,作用域的概念开始发挥作用。
作用域是程序的一部分。从这个部分可以直接访问命名空间,并且不需要任何前缀。
在任何给定时刻,至少有三个嵌套作用域。
具有本地名称的当前函数的作用域
具有全局名称的模块的作用域
具有内置名称的最外部作用域
在函数内部进行引用时,会先在本地命名空间中搜索名称,接着在全局命名空间中搜索,最后在内置命名空间中搜索。
如果另一个函数内有一个函数,则新作用域嵌套在本地作用域内。
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 ,那么所有的引用和赋值都会转移到全局 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”。
Python if...else 语句Python 运算符