python的模块

Python将函数定义和变量定义放在单独的文件中,这些文件称为模块(module),文件名就是模块名字加上.py。模块可以用 import 导入。每个模块有自己的名字存储在 __name__ 变量中,主模块的名字是 "__main__”。总结来说Python的一个文件就是一个模块,模块是以文件的方式组织。

当导入一个模块时,解释器先从内置模块(built-in module)开始搜索,如 sys 模块,如果没有找到就从 sys.path 指定的路径搜索。(所以那次我把模块名字定义为 parser 在 windows 下导入的却是内置的 parser 模块)sys.path 是一个序列,Python运行时会从头至尾逐一查找直到最终找到对应的模块定义。当导入模块失败时会抛出 ImportError,通过捕获来选择一个备选的模块。sys.modules 则是一个模块名对应模块所在位置的字典。sys.path 包含的目录包括脚本所在目录,PYTHONPATH指定的目录以及Python默认查找目录,脚本所在目录在最前面,是在内置模块之后优先查找的。sys.path在程序启动之后可以动态修改。

每个模块定义了自己的名称空间(namespace)。每个模块都有自己的私有的全局符号表(global symbol table)包含其所有使用的全局变量,因而不会与别的模块甚至主模块中的变量有任何冲突。引用模块中的函数、变量使用 modname.itemname 语法,模块中的任何全局变量都在此名称空间中。

当引用一个名字如foo时,Python依次locals()globals()__builtins__中查找,它们分别被称作局部名称空间、全局名称空间和内建名称空间。Python的名称空间是一个极其重要的概念,包括所有函数、模块、类、实例都可以用作名称空间,可以放入任何想要的东西。这跟Python的面向对象中的概念遥相呼应。《The Zen of Python》中说“Namespaces are one honking great idea – let’s do more of those!”

如果在顶层导入,模块将放在全局符号表中,如果在函数中导入,模块将放在函数的局部符号表中。模块中的最外层语句是用来初始化模块的只在第一次被导入时执行,如果想多次执行调用 reload(modulename) 方法。import的语法如下:

1
2
3
4
5
6
import modname
import modulename as mymodule
from modname import itemname1, itemname2
from modname import *
from modname import itemname  as myitem
from __future__ import new_feature

被导入的名字其实质是创建一个变量指向对应的值。这句话的含义是如果 a 模块中有一个b属性,值为100。from a import b 如果 b=200,此时 a 中的 b 还是100,改变的只是当前作用域中那个变量 b 指向的值。如果 b 是序列,并且调用 append() 改变了此序列,那么两个 b 的值还是一样的。之所以赋值为200会使得两个地方不一致的另外一个原因是:Python中数字与字符串一样是不可变对象,赋值改变的是对象的引用。

from __future__ 的作用是让程序员能够使用即将到来的新特性,这些新特性将会在以后的版本中加入到语言中来,那个时候不用 import 就可以使用这些特性,但是使用 import 依然有效。已经加入到 __future__ 中的特性描述(feature description)是不会删除的。在 Lib/__future__.py 中指定了特性可以开始使用的版本号(OptionalRelease),以及正式加入语言的版本号(MandatoryRelease),只有在OptionalRelease才能使用,之前会抛出 ImportError。现在支持的特性有:nested_scopes, generators, division, absolute_import, with_statement, print_function, unicode_literals

Python中有包(package)的概念,用来聚合相关的多个模块。包用文件夹的形式组织,形如A.B子模块就是在 A 文件夹中的 B.py 文件。包中必须包含 __init__.py 文件,否则将会被当做普通文件夹对待,__init__.py 可以是空文件,但必须存在。从包中导入模块的语法与上述类似。

1
2
3
import sound.effects.echo
from sound.effects import echo
from sound.effects import echo as sound_echo

from package import item 中的 item可以是子包、子模块或者函数、变量、类型。import item.subitem.subsubitem 要求item、subitem必须是包,subsubitem必须是子模块或者子包。导入子模块将导入它的父包。

__init__.py 文件用于导入包时执行初始化,其中定义的任何变量、函数或者导入的子模块将作为包的属性。特殊变量 __all__ 是一个包含子模块名字的列表,当 from package import * 时,__all__ 中所有子模块都将被导入。

在python2.x中,如果一个子模块需要导入一个兄弟子模块只需要,import sibling_mod 即可,Python会优先查找当前目录,如果找不到才会从标准搜索路径中查找,这种特性称为隐式相对导入(relative import)。到了Python3.x中已经不支持这种特性了,明确所有包的导入都必须是绝对导入(absolute import),相对导入需要用如下语法:

1
2
3
4
from . import echo
from .. import formats
from .echo import echofilter
from ..filters import equalizer

从Python2.5开始支持这种显式相对导入,提倡多用显式相对导入。

Python源文件编译成字节码后在相同目录下以.pyc结尾,如果提供 -o 参数将编译为.pyo文件。编译后的字节码文件执行起来不会比直接执行源文件更快,唯一的区别就是加载起来更快。

dir(module_name) 函数用来显示模块的全局符号表,返回值是一个排好序的字符串序列。