模块 Modules
一个模块是一个包含 Python 定义和函数的文件,其模块名就是文件名。
模块的最小组织单位是文件。
可以通过模块的 __name__ 全局变量查看模块名。
模块可以直接通过 python module.py <arguments> 执行,
会依次执行模块的每一行代码,此时模块的 __name__ 属性为 __main__ 。
因此我们可以在模块的最后用
if __name__ == "__main__":
pass来执行模块。
包 Packages
为了协助组织模块并土工名称层次解构,Python 引入了包的概念。 为了方便理解,可以将包看成是文件系统的目录,模块看成是目录中的文件。
需要注意的是: 所有的包都是模块,但并非所有的模块都是包。即,包是特殊的模块。 任何具有
__path__属性的模块都会被当作包。
Python 定义了两种类型的包,常规包和命名空间包。
常规包是传统的包类型,通常以一个包含 __init__.py 文件的目录形式存在。
当一个常规包被导入时,这个 __init__.py 文件会被隐式的执行。
模块导入机制
一个模块内的 Python 代码通过 import 操作就可以访问另一个模块内的代码。
import 是最常见的导入机制, importlib.import_module() 以及 __import__() 也可以进行导包。
import 语句结合了两个操作,它先搜索指定名称的模块,然后将搜索结果绑定到当前作用域中名称。
import res
from ttt import res
import ttt as res上诉三种导包都是将搜索到的包绑定到当前作用域的 res 变量上。
当 import 语句被执行时,会调用内置函数 __import__() 函数。
其他导包机制可以使用其自定义的方法实现导包。
TODO 搜索路径(QUESTIONS)
当我们要导入某个模块时,模块的搜索路径为:
- Python 内置(built-in)模块。
内置模块主要是用
C写的(os.py也是标准库),提供了对系统功能的访问。 内置模块虽然不是标准库,但可以划分到标准库的分类中。 sys.path- 执行文件的当前目录
PYTHONPATH- 依赖包
site-packages
因此,如果本地的模块名和 Python 标准库同名,则会覆盖。
判断标准库是否是内置模块的方法:
- 标准库可以被覆盖,内置模块不可以。
sys.built_in_modules
其实这仍然是个不清不楚的问题,详情可以去看 stackoverflow 。
而且这里 Modules 和 Importing 两个地方的描述并不相同, 但我感觉是在描述同一个问题,只能等之后看源码理解了。
相对导入
导入的起始模块未必是从包路径开始,使用 . 或者 .. 的方式是显示相对导入,否则是隐式的。
Python3 针对隐式相对导入会直接抛错。
绝对导入
从包的根路径开始导入。
开发 Lib 构建
在开发的时候,可以通过执行 python setup.py develop 安装当前开发的包,
这个命令会在当前环境的 site-packages 目录下创建 .egg-link 文件,指向当前开发的包,
因此等价与将包安装到了当前环境,就可以直接使用脚本方式运行了。