模块
模块是python中的最高组织单元,在物理层面上,模块以文件存储,模块的文件名就是模块的名字.py,每个模块都有自己的名称空间。
python按照路径搜索来查找模块文件,在PYTHONPATH环境变量中的路径为Python模块的搜索路径,通过sys.path属性可以看到模块搜索路径的列表,python按照这个列表的顺序对模块进行搜索,所以在路径列表前面的路径搜索到模块之后就不会继续搜索。由于该值是一个列表,可以通过sys.path.append方法,或者sys.path.insert方法添加路径到该列表中,或者通过sys.path.pop方法将某些路径排除到搜索路径之外等等。
包
模块的物理层面是文件,包就是有层次的特殊文件结构,特殊的点在于,每个目录下面都必须有__init__.py文件,如果没有该文件,则只是一个普通的文件目录,并不能作为包导入。这是因为导入包的原理其实就是导入该包的路径下面的__init__.py,其中包含可以导入的各种模块。
模块导入和加载
通过import、from ? import语句导入一个模块,或者通过as给模块起别名,模块只有在第一次导入的时候才会被加载,模块加载时,其实就是执行模块中的所有语句,此时,如果模块中除了定义的类和方法之外,在顶级作用域下有代码时,这些代码会被执行,所以在模块编写中需要避免在顶级作用域下直接执行代码。
在模块第一次被导入时,往往会比较慢,这是因为python在导入一个新的模块时,会从模块所在目录检查是否有.pyc文件,如果没有该文件,则会将模块编译成字节码,从而提高下一次导入的效率。
python也可以从一个ZIP文件中导入模块,该ZIP文件会被看成一个包,然而python不会再生成.pyc文件到该ZIP文件中,所以导入效率相对较低一些。
名称空间
名称空间指标示符到对象的映射,python在执行过程中,有两个或者三个活动的名称空间:局部名称空间、全局名称空间、内建名称空间。内建名称空间的所有名字都包含在__builtins__模块中,该模块又包含__buitin__模块,该模块中包含内建函数、异常以及其他属性,每一个python程序执行之前都会先导入__builtins__模块,每个模块都有自己的名称空间,导入一个模块时,会加载执行模块的全局名称空间,这也是为什么在加载一个模块时,所有顶级作用域下的代码会直接执行。
名称空间和作用域的关系:所有局部名称空间的名称都在局部作用范围内,局部名称空间之外的所有名称都在全局作用范围内。局部名称空间和作用域会随着函数的调用而不断变化,但是全局名称空间是不变的。名称空间决定一个变量名字是否存在,而作用域决定一个变量名字是否可以被访问到。通过globals()、locals()内建函数可以判断出某一名字属于哪个名称空间。在访问一个属性的时候,会从局部名称空间、全局名称空间、内建名称空间中寻找该名字,如果都找不到则会返回一个NameError的错误,由于寻找时总是先去寻找局部名称空间,所以局部名称空间中如果有和全局名称空间中的变量重名,则会讲全局名称空间中的变量“覆盖”(其实是不会再被找到)。
内建函数
__import__()函数,实际上import语句调用的就是__import__()函数来完成工作,通过重写该函数,可以自定义导入算法,也可以使用md=__import__(‘module’) ,相当于 import module as ad。
globals()、locals() 返回全局名称空间和局部名称空间的字典,其键为名称空间中的名字。
reload()函数可以从新加载一个模块,顾名思义,会讲模块从新执行一次。