个性化阅读
专注于IT技术分析

python3名称空间和作用域 – Python3教程

上一章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变量作用域

尽管定义了各种独特的名称空间,但我们可能无法从程序的每个部分访问所有名称空间,因而作用域的概念开始发挥作用。

作用域是程序的一部分,从这里可以直接访问名称空间,而不需要任何前缀。

在任何给定时刻,至少有三个嵌套作用域。

  • 具有本地名称的当前函数的作用域
  • 具有全局名称的模块的作用域
  • 具有内置名称的最外层作用域

当在函数内部创建引用时,将在本地名称空间中搜索该名称,然后在全局名称空间中搜索,最后在内置名称空间中搜索。

如果在另一个函数中有一个函数,则在局部作用域内嵌套一个新作用域。

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。

赞(0)
未经允许不得转载:srcmini » python3名称空间和作用域 – Python3教程

评论 抢沙发

评论前必须登录!