实际上,程序通常涉及不只一个文件。除了最简单的脚本之外,程序一般将采用多文件系统的形式,即使能够自己编写单个文件,也一定会使用到其他人已经写好的外部文件。

Python程序架构是将一个程序分割为源代码文件(也就是模块)的集合,并将这些集合连接成整体的方式。正如我们将要看到的那样,Python鼓励模块化的程序结构,将功能相近的可重用单元组织在一个模块中,这种方式符合直觉,同时也合乎直觉。在这个过程中,我们也会探索Python模块、导入以及对象属性这三个核心概念。

如何组织一个程序

从本质上讲,一个Python程序包括了多个含有Python语句的文本文件。程序拥有一个主体的顶层文件,辅以零个或多个被称为模块的支持文件。

以下是模块的工作原理。顶层文件(又称为脚本)包含了程序的主要控制流程:这就是你用来启动应用程序的文件。而模块文件是工具库,这些文件中收集了顶层文件(或者其他可能的地方)要使用的组件。顶层文件使用了在模块文件中定义的工具,而这些模块又有可能使用了其他模块所定义的工具。

尽管模块文件也是代码文件,但它们通常在运行时不需直接做任何事。作为替代,它们定义的工具会在其他文件中使用。在Python中,一个文件通过导人一个模块来获得这个模块定义的工具的访问权,这些工具被认为是这个模块的属性(即附加到模块对象的名称,例如函数)。总而言之,我们导入了模块、获取它的属性从而使用其中的工具。

导入和属性

下图是一个包含三个文件的Python程序的草图:​​a.py​​​、​​b.py​​​和​​c.py​​​。文件​​a.py​​​是顶层文件,它是一个由语句组成的简单文本文件,在运行时这些语句将从上至下执行。文件​​b.py​​​和​​c.py​​​是模块,它们也是含有语句的简单文本文件,但是它们通常并不是直接运行。就像之前解释的那样,取而代之的是,模块通常被想要使用它们的文件导入。
系统学习Python——模块和包:Python程序架构_包
例如,​​​b.py​​​定义了一个名为​​spam​​​的函数,供外部来使用。就像我们提到的那样,​​b.py​​​中包含一个Python的​​def​​语句来生成函数,这个函数会在之后通过给函数名后的括号中传入零个或更多的值来运行:

def spam(text)                              #File b.py
print(text, 'spam')

现在,假设​​a,py​​​想要使用​​spam​​​。为了实现这个目标,​​a,py​​中也许要包含如下这样的Python语句:

import b                         # File a.py 
b.spam('gumby') # Prints "gumby spam"

第一条Python的​​import​​​语句,给文件​​a,py​​​提供了由文件​​b.py​​​在顶层所定义的所有对象的访问权限。代码​​import b​​​可以大致理解为:载入文件​​b.py​​​,并给我能通过变量名​​b​​获取它所有的属性的权限。

为了达到这样的效果,​​import​​​以及​​from​​​语句会按需运行并载入其他的文件。更确切地说,在Python中,跨文件的模块链接在运行时​​import​​​语句执行后才会进行解析。实际效果就是,​​import​​​语句将模块名(可以简单地认为是变量名)赋值了载入的模块对象。事实上,在一个​​import​​语句中的模块名起到两个作用:识别加载的外部文件,同时它也会变成赋值了被载入模块的变量。

类似的,模块中定义的对象也会在运行时被创建,即在​​import​​​执行时。​​import​​​原则上会逐行运行在目标文档中的语句从而构建其中的对象。与此同时,每个在文件顶层赋值的名称都变成了模块的一个属性,这些属性可以被导入者访问。例如,​​a,py​​​中的第二行语句通过使用对象属性语法,调用了模块​​b​​​中所定义的函数​​spam​​​(​​spam​​​在导入过程中通过运行​​def​​​语句而创建)。代码​​b.spam​​​可以理解为:取出存储对象​​b​​​中名称为​​spam​​的值。

在这个例子中,​​spam​​​碰巧是个可调用的函数,所以我们可以在小括号内传入字符串​​'gumby'​​​。如果你亲自编写了这些文件,并在保存之后执行​​a.py​​​,那么字符串​​'gumby spam'​​就会被打印出来。

如前所述,在Python脚本中随处可见​​object.attribute​​​这种表示法:多数对象都有一些可用的属性,可以通过​​.​​运算符取出。有些是像函数这样可调用的对象,而其他的则是用来表示静态对象和属性的简单数据数值。

导人的概念在Pytho之中贯穿始终。任何文件都能从任何其他文件中导入其工具。例如,文件​​a.py​​​可以导入​​b.py​​​从而调用其函数,而​​b.py​​​也可能导人​​c.py​​​以利用定义在其中的不同工具。导入链要多深就有多深:在这个例子中,模块​​a​​​可导人​​b​​​,而​​b​​​可导人​​c​​​,​​c​​​可以再导入​​b​​,诸如此类。

除了作为最高级别的组织结构外,模块以及模块包也是Python中程序代码重用的最高层次。在模块文件中编写组件,可让原有的程序以及任何其他之后可能编写的程序得以使用。例如,编写上图中的程序后,我们发现函数​​b.spam​​​是通用的工具,可在完全不同的程序中再次使用。而我们所需要做的,只是从其他程序文件中再次导人文件​​b.py​​。

标准库模块

注意上图最右侧的部分。程序导入的模块有一些是由Python自身提供的,而不是你所需要编写的。

Python自带了很多实用的模块,称为标准库。根据最近的统计,这个集合体有超过200个模块,包含与平台无关的常见程序设计任务:操作系统接口、对象持久化、文本模式匹配、网络和Internet脚本、GUI建构等。虽然这些工具都不是Python语言的组成部分,但是你可以在任何安装了标准Python的环境下,通过导人适当的模块来使用它们。因为这些都是标准库模块,所以你可以理所当然地认为它们一定可用,而且在执行Pytho的绝大多数平台上都可运行。为了更全面地了解Python标准库模块,我们可以查看Pythor标准库参考手册,这份手册在Python安装后就可以看到,或者也可以使用​​https://www.python.org/​​的在线版本。

因为有如此繁多的模块,这是唯一了解有哪些工具可以使用的方式。我们也可以在涉及应用级程序设计的商业书籍中找到Python库工具的教程,例如《Python编程》,不过手册是免费的,可以用任何网页浏览器查看(属于HTML格式),也可以使用其他方式(例如Windows中的帮助功能),而且每次Python发行时都会更新。