返回介绍

模块命名空间

发布于 2024-01-29 22:24:16 字数 2027 浏览 0 评论 0 收藏 0

模块最好理解为变量名的封装,也就是定义想让系统其余部分看见变量名的场所。从技术上来讲,模块通常相应于文件,而Python会建立模块对象,以包含模块文件内所赋值的所有变量名。但是,简而言之,模块就是命名空间(变量名建立所在的场所),而存在于模块之内的变量名就是模块对象的属性。我们会在本节讨论这是如何运作的。

文件生成命名空间

那么,文件如何变成命名空间的呢?简而言之,在模块文件顶层(也就是不在函数或类的主体内)每一个赋值了的变量名都会变成该模块的属性。

例如,假设模块文件M.py的顶层有一个像X=1这样的赋值语句,而变量名X会变成M的属性,我们可在模块外以M.X的方式对它进行引用。变量名X对M.py内其他程序而言也会变成全局变量,但是,我们需要更正式地说明模块加载和作用域的概念以了解其原因。

·模块语句会在首次导入时执行。系统中,模块在第一次导入时无论在什么地方,Python都会建立空的模块对象,并逐一执行该模块文件内的语句,依照文件从头到尾的顺序。

·顶层的赋值语句会创建模块属性。在导入时,文件顶层(不在def或class之内)赋值变量的语句(例如,=和def),会建立模块对象的属性,赋值的变量名会存储在模块的命名空间内。

·模块的命名空间能通过属性__dict__或dir(M)获取。由导入而建立的模块的命名空间是字典;可通过模块对象相关联的内置的__dict__属性来读取,而且能通过dir函数查看。dir函数大至与对象的__dict__属性的键排序后的列表相等,但是它还包含了类继承的变量名。也许不完整,而且会随版本而异。

·模块是一个独立的作用域(本地变量就是全局变量)。正如第17章所显示的,模块顶层变量名遵循和函数内变量名相同的引用/赋值规则,但是,本地作用域和全局作用域相同(更正式的说法是,遵循我们于第17章提及的LEGB范围规则,但是没有L和E搜索层次)。但是,在模块中,模块范围会在模块加载后变成模块对象的属性辞典。和函数不同的是(本地变量名只在函数执行时才存在),导入后,模块文件的作用域就变成了模块对象的属性的命名空间。

以下是这些概念的示范说明。假设我们在文本编辑器中建立如下的模块文件,并将其命名为module2.py。

这个模块首次导入时(或者作为程序执行时),Python会从头到尾执行其中的语句。有些语句会在模块命名空间内创建变量名,也就是副作用,而其他的语句在导入进行时则会做些实际工作。例如,此文件中的两个print语句会在导入时执行。

但是,一旦模块加载后,它的作用域就变成模块对象(由import取得)的属性的命名空间。然后,我们可以结合其模块名,通过它来获取命名空间内的属性。

此处,sys、name、func以及klass都是在模块语句执行时赋值的,所以在导入后都变成了属性。我们会在第六部分讨论类,但是请注意sys属性:import语句其实是把模块对象赋值给变量名,而文件顶层对任意类型赋值了的变量名,都会产生模块属性。

在内部模块命名空间是作为辞典对象进行储存的。它们只是普通字典对象,有通用的字典方法可以使用。我们可以通过模块的__dict__属性获取模块命名空间字典(别忘了在Python 3.0中将其包含到一个list调用中——它是一个视图对象):

我们在模块文件中赋值的变量名,在内部成为字典的键。因此这里多数的变量名都反映了文件中的顶层的赋值语句。然而,Python也会在模块命名空间内加一些变量名。例如,__file__指明模块从哪个文件加载,而__name__则指明导入者的名称(没有.py扩展名和目录路径)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文