
1.3 导入代码
假设你有一段Python代码,需要在多个文件中使用。方法之一是,在每次需要该代码时,都进行复制和粘贴。这不仅费时而无聊,而且如果你想对代码做一些改动,则需要打开每一个粘贴有这段代码的文件,然后以同样的方式修改它。可想而知,这样编写软件的效率不高。
幸运的是,Python提供了一个共享代码的强大功能:模块导入。当模块b导入模块a时,模块b可以访问模块a中的代码。这使我们可以在某处编写程序,然后跨文件共享。让我们以本书第二部分将要编写的两个模块为例。
假设有两个模块:point.py和vector.py。这两个模块都在前面提到的包中:

第一个模块point.py定义了几何基元——点,第二个模块vector.py定义了另一个几何基元——向量。图1-1是两个模块的图示。每个模块都分为两个部分:灰色区域代表从其他地方导入的代码,白色区域代表模块自身定义的代码。
现在,假设point.py模块的某些功能需要使用向量(例如,使用向量移动某个点),我们可以使用Python的import命令访问vector.py中的向量代码。图1-2描绘了这个过程,Python将向量代码带到point.py的“导入区”,使它在模块内部可以被使用。

图1-1 两个Python模块

图1-2 从vector.py导入Vector类
在图1-2中,我们使用了如下Python命令:

这个命令只从vector.py中获取Vector类,不会导入其他任何东西。
下面将会介绍几种模块导入方法。
不同的导入形式
为了理解导入模块和模块内实体的不同方法,我们需要使用Mechanics项目的两个包:

在本例中,我们会使用geom2d和eqs包的各两个文件,或者模块。每个模块都定义了一个与模块同名的类,类名的首字母大写。例如,point.py模块定义了Point类,vector.py模块定义了Vector类,matrix.py模块定义了Matrix类。图1-3展示了包的结构。

图1-3 Mechanics项目中的两个包和它们的部分模块
记住这个目录结构,让我们分析几个场景。
(1)导入同一个包的模块
在geom2d包的point.py模块中,如果想导入整个vector.py模块,我们可以使用以下方法:

这样我们就可以使用vector.py中的内容,如下所示:

请注意,由于我们导入的是整个模块,而不是它的某个实体,因此我们必须用模块名称来指向该模块中定义的实体。如果想给被引用的模块一个不同的名称,我们可以给它重命名:

然后可以这样使用它:

我们还可以从模块中导入特定的名称,而不是整个模块。正如你前面所看到的,它的语法如下:

使用这种导入方式,我们可以执行如下操作:

在这种情况下,我们还可以重命名导入的名称:

当我们为一个导入的名称起别名时,我们只需将其重命名为其他名称。在本例中,代码可以写成如下形式:

(2)导入不同包的模块
如果想在matrix.py模块中导入point.py模块,那么由于point.py在不同的包中,我们可以如下操作:

或者

这让我们可以在matrix.py中使用point.py模块的全部内容:

同样,我们可以对导入的模块重命名:

或者,等价地:

用这两种方式,我们都可以使用pt如下:

我们还可以从模块中导入特定的名称,而不是整个模块,如下所示:

与前面一样,我们可以使用一个别名:

(3)相对导入
最后是相对导入。相对导入(relative import)是指导入模块所使用的路径是相对路径,其起点是文件的当前位置。
我们用一个点(.)指代同一个包内的模块或包,用两点(..)指代该包的父级目录。
同样是前面的例子,我们可以使用相对导入在matrix.py内导入point.py模块:

上述代码中,路径..geom.point的含义是:从当前的目录移动到父级目录,然后定位point.py模块。