热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

命名空间_Python基础篇:作用域和命名空间

命名空间和作用域的概念我们之前也提到过,比如内置函数globals(),函数中变量的作用域,模块使用的import等等。这些可能让我们对这

命名空间和作用域的概念我们之前也提到过,比如内置函数globals(),函数中变量的作用域,模块使用的import等等。这些可能让我们对这两个概念有了大致的理解。本节再详细探讨一下。

3067b04fb39871279bd0e3f703ab1d7e.png

Python命名空间

命名空间,就是一个从名称到对象的映射关系。

对于这个概念的理解,我们打个比方:河西村有个人(对象)叫张三(名称),河东村有个人(对象)也叫张三(名称),俩人虽然都叫张三(名称),但是他们俩不是同一个人(对象),因为他们属于不同的村(命名空间)。有一天,河西村的张三名声大了,传播到镇上了(名称被import到“镇”这个空间),镇上的人讲起“张三”时,就是说的河西村的,要是说河东村的张三,就要特别说“河东村的张三”(河东村.张三)。这就是命名空间的意思——映射了名称到对象的名称范围。

目前,大部分的命名空间都是由Python的字典实现的,通常我们不会去关注它们,处理要面对性能问题时,并且这种实现可能在将来改变。所以说,我们不需要深究命名空间的内部实现,但要搞明白它的使用。

b0f64ef3388517189225e708188956c8.png

下面是几个命名空间的例子:

  • 内置函数的集合(包含print()等内置函数和内置异常等);
  • 模块中的全局名称;
  • 函数调用中的本地名称。

另外,从某种含义上说,对象的属性集合也是一种命名空间的形式。正如我们前面举的张三的例子那样,不同命名空间中的名称之间没有任何关系。比如,两个不同模块都可以定义函数max()而不会产生混淆,模块的用户要调用某个max()函数就要在其前面加上模块名称。(详见import的使用)

Python属性

我们把任何跟在一个点号之后的名称都称为属性。例如,在表达式a.name中,real是对象a的一个属性。同样对模块中函数的引用也是属性引用,在表达式modname.funcname中,modname是一个模块对象,而funcname是它的一个属性。

属性可以是只读的也可以是可写的。如果是可写的,那么我们就可以对属性进行赋值,比如,modname.name = '猿人学Python'。可写的属性同样可以用del语句删除,比如del modname.name将把modname对象的name属性移除。

不同时刻创建的命名空间有不同的生存期:

  • 包含内置名称的命名空间是在Python解释器启动时创建的,永远不会被删除(除非退出解释器);
  • 模块的全局命名空间在模块定义被读入(import)时创建,通常,模块命名空间也会持续到解释器退出;
  • 从脚本文件(.py或.pyc)读取或交互式(解释器shell)读取而被解释器的顶层调用执行的语句,被认为是__main__模块调用的一部分,它们有自己的全局命名空间;
  • 函数的本地命名空间创建于该函数被调用的时刻,并且在函数返回或抛出一个不在函数内部处理的异常时被删除。递归函数的每次递归调用都会创建它自己的本地命名空间;

内置名称实际上也存在于一个模块中,它叫做builtins。

f21cecd757abbd4c1b56bf8705a7c9bd.png
Python作用域

作用域,是一个命名空间可直接发放完的Python代码的文本区域。这里的“可直接访问”的意思是,对名称的不加点号(非限定性)引用会尝试在命名空间中查找该名称。

尽管作用域是静态确定的,但它们是动态使用的。在执行期间的任何时刻,至少有三个嵌套的作用域,它们的命名空间可以直接访问:

  • 最内部作用域:最先搜索该作用域,包含局部名称
  • 封闭函数作用域:从最近的封闭作用域开始搜索,包含非局部名称,也包括非全局名称
  • 倒数第二个作用域:包含当前模块的全局名称
  • 最外面的作用域:最后搜索,是包含内置名称的命名空间

如果一个名称被声明为全局变量,则所有引用和赋值将直接指向包含该模块的全局名称的中间作用域。 要重新绑定在最内层作用域以外找到的变量,可以使用nonlocal语句声明为非本地变量。 如果没有被声明为非本地变量,这些变量将是只读的(尝试写入这样的变量只会在最内层作用域中创建一个新的局部变量,而同名的外部变量保持不变)。

很重要的一点:作用域是按文本方式确定的,模块内定义的函数的全局作用域就是该模块的命名空间,无论该函数从什么地方或以什么别名被调用。另一方面,实际的名称搜索是在运行时动态完成的。

Python 的一个特殊之处在于: 如果不存在生效的global语句,对名称的赋值总是进入最内层作用域。 赋值不会复制数据,它们只是将名称绑定到对象。删除也是如此,语句del x会从局部命名空间的引用中移除对x的绑定。事实上,所有引入新名称的操作都使用局部作用域,特别是import语句和函数定义会在局部作用域中绑定模块或函数名称。

global语句可被用来表明特定变量生存于全局作用域并且应当在其中被重新绑定;nonlocal语句表明特定变量生存于外层作用域中并且应当在其中被重新绑定。

下面我们来看一个作用域和命名空间的例子,它演示流量如何引用不同作用域和命名空间以及global和nonlocal如何影响变量绑定:

98b2815ef6a0c03b06b2721b9089ab15.png

思考一下,上面的代码会输出怎样的结果?如果你对上面的讲解理解透了,你的思考结果应该是这样的:

5ce5661d4dba62802df568338dea08c8.png

这里要说明的是,do_global()函数修改了全局变量name,并没有对scope_demo()函数的局部变量name做修改,所以打印了After global assignment: nonlocal name。

局部赋值(默认情况)不会改变scope_demo对name的绑定;nonlocal赋值会改变函数scope_demo对name的绑定,而global赋值会改变模块层级的绑定(不是scope_demo内部的name,而是其之外的全局作用域下的name)。

命令空间和作用域总结:

命名空间定义了一个名称的范围,作用域指定了能看到命名空间的文本区域(代码)。代码执行时,名称搜索的顺序和范围如下:

  • 最内部作用域:最先搜索该作用域,包含局部名称
  • 封闭函数作用域:从最近的封闭作用域开始搜索,包含非局部名称,也包括非全局名称
  • 倒数第二个作用域:包含当前模块的全局名称
  • 最外面的作用域:最后搜索,是包含内置名称的命名空间

相关练习题

参照scope_demo(),练习局部赋值、nonlocal赋值、global赋值。



推荐阅读
  • 本文介绍如何使用Python进行文本处理,包括分词和生成词云图。通过整合多个文本文件、去除停用词并生成词云图,展示文本数据的可视化分析方法。 ... [详细]
  • 本文详细介绍了Python中文件的基本操作,包括打开、读取、写入和关闭文件的方法,并通过实例展示了如何将Excel文件转换为CSV文件以及进一步转换为HTML文件。此外,还涉及了成绩等级替换的具体实现。 ... [详细]
  • andr ... [详细]
  • 根据最新发布的《互联网人才趋势报告》,尽管大量IT从业者已转向Python开发,但随着人工智能和大数据领域的迅猛发展,仍存在巨大的人才缺口。本文将详细介绍如何使用Python编写一个简单的爬虫程序,并提供完整的代码示例。 ... [详细]
  • Scala 实现 UTF-8 编码属性文件读取与克隆
    本文介绍如何使用 Scala 以 UTF-8 编码方式读取属性文件,并实现属性文件的克隆功能。通过这种方式,可以确保配置文件在多线程环境下的一致性和高效性。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 本文探讨了在Java中实现系统托盘最小化的两种方法:使用SWT库和JDK6自带的功能。通过这两种方式,开发者可以创建跨平台的应用程序,使窗口能够最小化到系统托盘,并提供丰富的交互功能。 ... [详细]
  • 本文介绍如何使用 Python 获取文件和图片的创建、修改及拍摄日期。通过多种方法,如 PIL 库的 _getexif() 函数和 os 模块的 getmtime() 和 stat() 方法,详细讲解了这些技术的应用场景和注意事项。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
  • 本文提供了使用Java实现Bellman-Ford算法解决POJ 3259问题的代码示例,详细解释了如何通过该算法检测负权环来判断时间旅行的可能性。 ... [详细]
  • 本文探讨了在Java多线程环境下,如何确保具有相同key值的线程能够互斥执行并按顺序输出结果。通过优化代码结构和使用线程安全的数据结构,我们解决了线程同步问题,并实现了预期的并发行为。 ... [详细]
  • Java第四周作业:条件语句实践与分析
    本次作业主要围绕Java编程中的if语句展开,通过具体案例深入理解选择结构的使用方法。学生需要完成多个编程任务,并在博客中详细记录每道题目的题目、代码及运行结果。 ... [详细]
author-avatar
mobiledu2502871653
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有