您的位置:首页 > 编程语言 > Python开发

Python 名称空间与作用域

2018-01-20 08:51 603 查看
这篇文章介绍 Python 的名称空间以及变量的作用域。

Python 的名称

Python 的名称(Name)是对象的一个标识(Identifier)。我们知道,在 Python 里面一切皆对象,名称就是用来引用对象的。说得有点玄乎,我们以例子说明。

例如,在
a = 2
这个语句中,
2
是个存储在内存中的一个对象,名称
a
则会引用
2
这个对象,“引用”的含义是指可以通过名称
a
来使用
2
这个对象。我们可以使用
id()
函数来获取对象的地址。

a = 2
print(id(2))
print(id(a))


输出:

43547988

43547988

可以看到,两都均指向同一个对象。我们再来看复杂一点的代码。

a = 2
print 'id(a) = %s' % id(a)
a = a + 1
print 'id(a) = %s' % id(a)
print 'id(3) = %s' % id(3)
b = 2
print 'id(2) = %s' % id(2)
print 'id(b) = %s' % id(b)


输出:

id(a) = 55606612

id(a) = 55606600

id(3) = 55606600

id(2) = 55606612

id(b) = 55606612

上述的代码发生了什么呢?我们以图1来说明。



图1:Python 的名称与对象

起初,名称
a
引用对象
2


然后,执行操作
a = a + 1
,这时对象
3
被创建,名称
a
引用对象
3
,所以
id(a)
id(3)
输出相同的地址;

最后,执行
b = 2
,名称
b
引用对象
2
,所以
id(2)
id(b)
输出相同的地址

这个例子也展示了 Python 在执行变量的赋值时,并不会重复创建一个对象的事实。名称采用动态绑定的机制使得 Python 更加高效,同一个名称可以引用不同类型的对象。

a = 5
a = 'hello world'
a = [1, 2, 3]


可以看到,
a
先后引用了数字,字符串,列表的类型的对象,这在 Python 中完全是合法的。

Python 的名称空间

了解 Python 的名称后,我们来看 Python 的名称空间。

名称空间是名称到对象的映射。

在 Python 中,名称空间采用字典来实现。Python 的名称空间包括:

内置名称空间,例如,内置名称空间包含 Python 的内置函数,如,
abs()


模块名称空间,全局名称空间,在模块内定义的名称

局部名称空间,例如,在函数(function)或者类(class)被调用时,其内部包含的名称

不同的名称空间内的名称不会相互冲突,即是它们采用相同的名称。这也正是名称空间的作用。

内置名称空间在 Python 解释器启动时就创建了,直到 Python 解释器退出时内置名称空间才失效。这使得我们可以在程序的任何位置使用内置名称空间内的名称,例如,
id()
print()
等函数。

模块名称空间当模块被引用时创建,直到 Python 解释器退出时模块名称空间才失效。

函数名称空间在函数被调用时创建,函数返回后失效。



图2:Python 的名称空间

Python 变量的作用域

Python 的作用域(scope)决定了我们在程序中能否直接使用名称空间中的名称,直接访问的意思是指不需要在名称前添加名称空间的前缀。对于 Python 来说,至少存在以下三类的作用域。

函数作用域,包括了函数内的局部名称

模块作用域,包括了模块内的全局名称

内置作用域,包括了内置名称

当在函数内部使用一个名称时,为了查找出该名称所引用的对象,Python 解释器先在函数名称空间查找,接着在模块名称空间查找,最后在内置名称空间查找,直到寻找到该名称为止。

当函数 A 处于函数 B 的内部时,函数 A 的作用域处于函数 B 作用域之内。

例子

def outer_function():
b = 20
def inner_func():
c = 30

a = 10


在这个例子中,名称
a
在全局名称空间中,名称
b
在函数
outer_function
的局部名称空间,名称
c
则在函数
inner_func
的局部名称空间。

当我们在函数
inner_func
时,
c
是个局部的名称,
b
是个非局部的名称,而
a
则是个全局的名称。在函数
inner_func
中,我们可以对
c
进行读取操作和赋值操作,而只能对
b
a
进行读取操作。当对
b
进行赋值时,一个新的名称将会被创建,这个新的名称处于
inner_func
函数局部名称空间中。对
a
进行赋值时也会在局部名称空间中创建一个新的名称。

我们使用以下的例子来说明。

def outer_function():
a = 20

def inner_function():
a = 30
print('a = %s' % a)

inner_function()
print('a = %s' % a)

a = 10
outer_function()
print('a = %s' % a)


输出:

a = 30

a = 20

a = 10

在函数
inner_function
中,我们对
a
进行了赋值操作,但函数
outer_function
中的
a
仍然为
20
,全局名称空间中的
a
则仍然为
10


为了在函数作用域中对全局的名称进行读取或者赋值操作,需要将这个名称声明为
global


def outer_function():
global a
a = 20

def inner_function():
global a
a = 30
print('a = %s' % a)

inner_function()
print('a = %s' % a)

a = 10
outer_function()
print('a = %s' % a)


输出:

a = 30

a = 30

a = 30

可以看到,通过
global
,我们在不同的作用域对全局名称
a
进行了赋值操作,最后在函数
inner_function
中对
a
的赋值也就是全局名称
a
的值。

参考资料

https://www.programiz.com/python-programming/namespace

https://docs.python.org/3/tutorial/classes.html

https://www.python-course.eu/namespaces.php

https://www.python-course.eu/global_vs_local_variables.php

https://www.programiz.com/python-programming/modules

https://code.tutsplus.com/tutorials/what-are-python-namespaces-and-why-are-they-needed–cms-28598

https://bytebaker.com/2008/07/30/python-namespaces/

https://stackoverflow.com/questions/3190706/nonlocal-keyword-in-python-2-x
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: