在Python中,一个.py文件就称之为一个模块(Module)。使用模块还可以避免函数名和变量名冲突。为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。引入了包以后,模块名字就变为“包的文件夹名.模块的文件名”。

模块(module)

编辑

模块(module)可以是下述实体:

  • Python文件(.py)
  • Unix与Linux的共享对象,其后缀为.so
  • Windows的DLL,后缀为.pyd
  • 目录,并应包含一个__init__.py文件。

任何模块代码的第一个字符串都被视为模块的文档注释;

Python的搜索路径sys.path,这是一个列表,包含了:

  • 当前进程的根目录
  • PYTHONPATH 环境变量指定的路径列表。
  • Python 标准库目录列表。
  • 路径文件 (.pth) 保存的目录 (通常放在 site-packages目录下)

虚拟机按以下顺序匹配目标模块:

  • py 源码文件。
  • pyc 字节码文件。
  • egg 包文件或目录。
  • so、dll、pyd 等扩展文件。
  • 内置模块。
  • 其他。

Python模块,可由import命令加载:

import module1[ as aliasname, module2[,... moduleN]

一个模块只会被导入一次,不管执行了多少次import语句。模块的名字追加到了当前符号表,但没有把该模块中的函数名称写入到当前符号表里。

从模块中导入一个指定的部分到当前命名空间中,语法如下:

from modname import name1[ as alisasname, name2[, ... nameN]]
from module2 import *

每个模块有自己独立的符号表,在模块内部的函数当作全局符号表来使用。

模块内部__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,如下列。类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,即它们应视作模块私有的名字。

  • __name__属性,其值为模块名 <package>.<module>;当其值是'__main__'时,表明该模块自身在运行,否则是被引入。
  • __file__: 模块完整⽂文件名。
  • __dict__: 模块 globals 名字空间。
  • __doc__:模块定义的文档注释

内置函数 dir() 以字符串列表的形式返回指定模块内定义的所有名称。

可以应对包不存在的异常:

try:
 import custommodule
except ImportError:
 pass

sys.modules 是一个字典,它包含了从 Python 开始运行起,被导入的所有模块。键字就是模块名,键值就是模块对象。列出已经导入的模块:

print('\n'.join(sys.modules.keys()))

每个 Python 类都拥有一个内置的类属性 __module__,它定义了这个类的模块的名字。

from math import cos
cos.__module__

卸载一个模块:

del sys.modules["moduleName"]

可⽤用 imp.find_module() 获取模块的具体⽂文件信息:

imp.find_module("numpy")

import的本质

编辑

import一个模块module_name,实质上是创建一个同名变量(module_name),其类型是module。并在sys.modules中创建一个键值对。该模块中的全局代码也会被执行。

import一个模块时,首先查看sys.modules是否已经有了该模块。如果有了该模块,则无操作。

显然,在一个模块中import另一个模块,也是在sys.path中搜索。

包(package)

编辑

包,是多个模块的组织体系。目录只有包含一个叫做 __init__.py 的文件(哪怕是空文件)才会被认作是一个包。否则,Python就把这个目录当成普通目录。__init__.py本身就是一个模块,而它的模块名就是包名。Python3中的包,__init__.py文件并不是必须的。__init__.py文件在包或内部模块导入时自动执行,且仅执行一次。

可以有多级目录,组成多级层次的包结构。

如果包定义文件 __init__.py 存在一个叫做 __all__ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。如果 __all__ 没有定义,使用 from 包.子包 import * 这种语法的时候,不会导入包里的任何子模块,只是把包和它里面定义的所有内容导入进来。

包内部的一个模块,可以如下引用这个包的其它模块:

from . import another_module

import

编辑
  • 第一种用法:import module_name
  • 第二种用法:from package_name import module_name

Python会在两个地方寻找模块或包:sys.path、运行文件所在的目录。python3采用绝对导入,即嵌套的import是根据最外层的运行文件的所在目录来导入。

相对导入的办法:

  • from . import module_name 导入和自己同目录下的模块
  • from .package_name import module_name 导入和自己同目录的包的模块。
  • from .. import module_name。导入上级目录的模块。
  • from ..package_name import module_name。导入位于上级目录下的包的模块。每多一个点就多往上一层目录。

如果运行文件使用了相对导入,就必须进入package_name所在目录,然后用python -m package_name.module_name来启动执行。

其他简单但实用的用法:

import moudle_name as alias

from module_name import function_name, variable_name, class_name。使用逗号可以导入模块中的多个元素。

有时候导入的元素很多,可以使用反斜杠来换行,官方推荐使用括号。

from Tkinter import Tk, Frame, Button, Entry, Canvas, Text, \
    LEFT, DISABLED, NORMAL, RIDGE, END	# 反斜杠换行

from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
    LEFT, DISABLED, NORMAL, RIDGE, END)	# 括号换行(推荐)