模块导入与重载——更大的模块故事:属性

未匹配的标注

因为导入操作在最后一步会执行文件,所以导入和重载提供了一个自然的程序启动选项。然而,从更广泛的角度来看,模块充当工具库的角色,如你将在 Part V 中详细学习的。然而,基本概念是简单的:模块通常只是变量名包,被称作命名空间,且在这个包中的名称被称为属性。一个属性仅仅是附在一个特定对象(如一个模块)上的变量名。

更具体地说,导入模块的程序可以访问到在模块文件顶层被分配的所有名称。这些名称通常被分配给被模块导出的工具——函数、类、变量等等——它们计划在其他文件和程序中被使用。在外部,模块文件的名称可以用两个Python语句来获取,importfrom,还有 reload 调用。

为了展示,使用文本编辑器使用下面内容,在工作目录创建一个名为 myfile.py 的单行Python模块文件:

title = "The Meaning of Life"

这可能是世界上最简单的Python模块之一(它只包含了一行赋值语句),但足以说明问题。当这个文件被导入时,它的代码被运行来产生模块的属性。也就是说,赋值语句创建了一个名为 title 的变量和模块属性。

你可以在其他组件中用两种不同方式来访问到这个模块的 title 属性。首先,你可以用 import 语句来整体加载模块,然后使用属性名称限定模块名称来获取它(注意我们这里让解释器自动打印):

% python # Start Python
>>> import myfile # Run file; load module as a whole
>>> myfile.title # Use its attribute names: '.' to qualify
'The Meaning of Life'

通常,点表达式语法 对象.属性 让你可以获取附在任何对象上的任何属性,且是Python代码中最常用的操作之一。这里,我们已经使用它来访问在模块 myfile 中的字符串变量 tilte——换句话说,myfile.title.

或者,你可以用 from 语句从模块中获取(其实,是拷贝)名称:

% python # Start Python
>>> from myfile import title # Run file; copy its names
>>> title # Use name directly: no need to qualify
'The Meaning of Life'

如你将在随后更详细地看到,from 就像 import,在导入部分有一个额外的名称赋值。技术上讲,from 拷贝了模块的属性,以至于他们在接收程序中都变成了简单的变量——因此,你这次可以简单地将导入的字符串引用为 title(变量)而不是 myfile.title(属性引用[7])。

使用 imporotfrom来引发导入操作,模块文件 myfile.py 中的语句都会被执行,且导入组件(这里,交互式提示符)可以访问分配在文件顶层的名称。在这个简单例子中只有一个这种名称——变量 title,被赋值了一个字符串——但当你开始在模块中定义对象如函数和类时,这里的概念会更加有用:这些对象成为可重用的软件组件,它们能从一个或多个客户端模块中通过名称访问。

在实践中,模块文件通常定义了不止一个名称在文件内外使用。下面是一个定义三个名称的例子:

a = 'dead' # Define three attributes
b = 'parrot' # Exported to other files
c = 'sketch'
print(a, b, c) # Also used in this file (in 2.X: print a, b, c)

这个文件,threenames.py,赋值了三个变量,因此对外部世界产生了三个属性。它还在一个 3.X print 语句中使用了它所拥有的三个变量,如当我们将其作为顶层文件运行时所看到的。(在Python 2.X 中 print 有一些不同,所以这里需要省略它的外部小括号来精确匹配输出;在第11章关于这点的更完整解释):

% python threenames.py
dead parrot sketch

在其他地方,当这个文件被首次导入时,其中所有代码也是照常运行,不管是通过 importfrom。使用 import 的本文件的客户端得到了模块和属性,然而使用 from 的客户端得到了文件中名称的拷贝:

% python
>>> import threenames # Grab the whole module: it runs
here
dead parrot sketch
>>>
>>> threenames.b, threenames.c # Access its attributes
('parrot', 'sketch')
>>>
>>> from threenames import a, b, c # Copy multiple names out
>>> b, c
('parrot', 'sketch')

这里的结果被打印在小括号中,因为它们其实是元组——一种被输出中逗号创建的对象(在本书的下一部分将会谈到)——因此你可以暂时安全的忽略它们。

一旦你开始使用像这样的多个名称编码模块,内置的 dir 函数就开始了有了用武之地——你可以用它来获取在模块中的所有可用名称的列表。下面在方括号(我们将在下一章中开始学习列表)中返回了一个Python字符串列表:

>>> dir(threenames)
['__builtins__', '__doc__', '__file__', '__name__', '__package__',
'a', 'b', 'c']

这里,这个列表的内容已经被编辑过了因为它们根据Python版本不同而不同。这里要注意的点是当像这样在括号中使用导入模块名称来调用 dir 函数时,它返回在那个模块中的所有属性。它返回的一些名称是你“免费”得到的:前后带有双下划线的名称(__X__)是内置名称,它们总是被Python预定义且对解释器有特殊含义,但在本书的这个节点上它们并不重要。代码中通过赋值定义的变量——a,b和c——在 dir结果中最后出现。


[7]: 注意 importfrom 都将模块文件名简单地列为 myfile而不带其 .py 扩展名后缀。如你将在 Part V 中学习到的,当Python查找真实文件时,它知道在其搜索程序中包含后缀。再一次,你必须在系统shell命令行包含 .py 后缀,但在 import 中不需要。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~