从实际的角度来看,模块往往对应于Python程序文件(或是用外部语言如C,Java或C#编写而成的扩展)。每一个文件都是一个模块,并且模块导入其他模块之后就可以使用导入模块定义的变量名。
模块可以由两个语句和一个重要的内置函数进行处理:
- import —— 使导入者以一个整体获取一个模块
- from —— 允许导入者从一个模块文件中获取特定的变量名
- imp.reload —— 在不终止Python程序的情况下,提供了一种重新载入模块文件代码的方法
模块
在模块顶层指定的所有变量名都会变成其属性,并且可以导出供客户端来使用。
因为模块名在Python程序中会编程变量名(没有.py),因此,应该遵循普通变量名的命名规则。
当一个模块被导入时,Python会把内部模块名映射到外部文件名。
客户端可以执行import和from语句:import会读取整个模块,from将获取模块特定的变量名。
标准库模块
import语句
程序第一次导入指定文件时,会执行三个步骤:
- 找到模块文件
- 编译成位码(需要时)
- 执行模块的代码来创建其所定义的对象
这三个步骤只在程序执行时,模块第一次导入时才会进行。在这之后,导入相同模块时,会跳过这三个步骤,而只提取内存中已加载的模块对象。从技术上讲,Python把载入的模块存储到一个名为sys,modules的表中,并在一次导入操作的开始检查该表。如果模块不存在,将会启动一个三个步骤的过程。
搜索
首先,Python必须查找到import语句所引用的模块文件。在标准的import中引入路径和后缀名等细节,从语法上讲是非法的,只能列出简单名称,路径和后缀是刻意省略的。
编译(可选)
导入之后,Python会检查文件的时间戳,如果发现字节码文件比源代码文件旧,就会在程序运行时自动重新生成字节代码。另一方面,如果发现.pyc字节码问价不比对应的.py源代码文件旧,就会跳过源代码到字节码的编译步骤。此外,如果Python在搜索路径上只发现了字节码文件,而没有源代码,就会直接加载字节码。
当文件导入时,就会进行编译。因此,通常不会看见程序顶层文件的.pyc字节码文件,除非这个文件也被其他文件导入:只有被导入的文件才会在机器上留下.pyc。顶层文件的字节码是在内部使用后就丢弃了。
运行
import模块的最后步骤是执行模块的字节码。文件中的所有语句都会依次执行。
模块变量名有两个不同目的:识别要被载入的外部文件,同时会生成脚本中的变量,在文件加载后,用来引用模块对象。
因为import使一个变量名引用整个模块对象,必须通过模块名称来得到该模块的属性。
from语句
from会把变量名复制到另一个作用域,所以它就可以让我们直接在脚本中使用复制后的变量名,而不需要通过模块:
>>>from module1 import printer
>>>printer('Hello world!')
我们可以直接使用变量名,而无须在嵌套模块名称之后。
from语句其实只是稍稍扩展了import语句而已,它照常导入了模块文件,但是多了一个步骤,将文件中的一个或多个变量名从文件中复制了出来。
from * 语句
当使用*时,会取得模块顶层所有赋了值的变量名的拷贝:
>>>from module1 import *
>>>printer('Hello world!')
import和from是赋值语句
就像def一样,import和from是可执行的语句,而不是编译期间的声明,而且它们可以嵌套在if测试中,出现在函数def之中等,直到执行程序时,Python执行到这些语句才会进行解析。
import和from都是隐形的赋值语句:
- import将整个模块对象赋值给一个变量名
- from将一个多个变量名赋值给另一个模块中同名的对象
模块路径
模块搜索路径
- 程序的主目录
Python首先会在主目录内搜索导入的文件。当你运行一个程序的时候,这个入口是包含程序的顶层脚本文件的目录。当在交互模式下工作时,这一入口就是你当前工作的目录。
由于这个目录是先搜索的,其文件也将覆盖路径上的其他目录中具有同样名称的模块
- PYTHONPATH目录(如果已经进行了设置)
之后,Python会从左至右搜索PYTHONPATH环境变量设置中罗列出的所有目录。
- 标准链接库目录
Python会自动搜索标准模块安装在机器上的那些目录,这些通常是不需要添加到PYTHONPATH之中或包含到路径文件中的。
- 任何.pth文件的内容(如果存在的话)
Python允许用户把有效的目录添加到模块搜索路径中去,也就是在后缀名为.pth的文本文件中一行一行地列出目录。
配置搜索路径
在Windows上,我们可能把PYTHONPATH设置为分号分隔开的一串目录,或者可以创建一个名为C:\Python30\pydirs.pth的文本文件。
sys.path列表
如果想看看模块搜索路径在机器上的实际配置,可以通过打印内置的sys.path列表来查看这个路径。
sys,path是模块搜索的路径,Python在程序启动时进行配置。
>>>import sys
>>>sys.path
模块文件(扩展名)选择
文件的后缀名是刻意从import语句中省略的。Pythin会选择在搜索路径中第一个符合导入文件名的文件。
import b形式的import可能会加载:
- 源代码文件b.py
- 字节码文件b.pyc
- 目录b,包导入
- 编译扩展模块,导入时使用动态连接
- 用C编写的编译好的内置模块,并通过静态连接至Python
- ZIP文件组件,导入时会自动解压缩
- 内存内映像,对于frozen可执行文件
- Java类,在Jython版本的Python中
- .NET组件,在IronPython版本的Python中
对于导入者来说,完全忽略了需要加载的文件类型之间的差异,无论是在导入时或者是在读取模块的属性时都是这样的,客户端不在乎文件是什么。
distutils工具
前面对模块搜索路径设置的说明,主要是针对自己编写的用户定义的源代码。Python的第三方扩展,通常使用标准链接库中的distutils工具来自动安装,所以不需要路径设置,就能使用它们的代码。
使用distutils的系统一般都附带setup.py脚本,执行这个脚本可以进行程序的安装。这个脚本会导入并使用distutils模块,将这种系统发在属于模块自动搜索路径一部分的目录内(通常是在python安装目录下的lib/site-packages子目录中)。
模块命名空间
简而言之,模块就是命名空间,而存在于模块之内的变量名就是模块对象的属性。
重载模块
模块代码默认只对每个过程执行一次。要强制使模块代码重新载入并重新运行,得调用reload内置函数。
reload函数
模块包
除了模块名之外,导入也可以指定目录路径。Python代码的目录就称为包,因此,这类导入就称为包导入。事实上,包导入是把计算机上的目录编程另一个Python命名空间,而属性则对应与目录中所包含的子目录和模块文件。
包导入
在import语句中列举简单文件名的地方,可以改成列出路径的名称,彼此以点号相隔:
import dir1.dir2.mod
from dir1.dir2.mod import x
这些语句中点号路径是对应于机器上目录层次的路径,通过这个路径可以获得到文件mod,py。容器目录dir0 (dir0 \ dir1 \ dir2 \ mod.py)需要添加在模块搜索路径中。
import语句中目录路径只能是以点号间隔的变量,不能在import语句中使用任何平台特定的路径语法。
__init__.py包文件
如果选择使用包导入,就必须多遵循一条约束:包导入的路径中的每个目录内都必须有__init__.py这个文件,否则导入包会失败。也就是说,dir1, dir2内都必须包含__init__.py这个文件,容器目录 dir0不需要这类文件。
也就是说,像这样的目录结构:
dir0 \ dir1 \ dir2 \ mod.py
以及这种形式的import语句:
import dir1.dir2.mod
必须遵循下列规则:
- dir1和dir2中必须都含有一个__init__.py文件
- dir0是容器,不需要__init__.py文件,如果有的话,这个文件也会被忽略
- dir0 必须列在模块搜索路径上
Python首次导入某个目录时,会自动执行该目录下__init__.py文件中的所有程序代码,文件的内容可以为空。
高级模块话题