module是一个Python文件,而package是一个目录结构。package中必须包含__init__.py, 该文件可以为空,主要作用是让python识别这个目录为package。
__init__.py中可以使用__all__这个列表来指定在from this_module import *时时,哪些模块会被自动载入
__all__ = [ 'test' ] module的字符串名
__init__.py会在import该package或者该package中的Module之前被执行,并且只执行一次。
当import package时,将会只执行该__init__.py,我们可以指定需要载入的子module。这样在载入该包后,这些module就可用了。
当from package import *时,__all__定义的是需要导入的模块
当from module import *时,__all__定义的是导入的名称
Module Hierachy
我们知道os是一个module,而path是os的sub module,他们不是以package的形式来组织的。如果我们要以module,submodule的形式来组织层级结构,比如os.path,那么我们该怎么做?
当我们import os.path时,其实python是这么来载入的这些module的
importing_process
1. search sys.modules
2. find a finder
call finder.find_modules(fullname), if found, return a loader
3. call loader.load_modules(fullname)
4. add to sys.modules
importing os (fullname = os)
importing path (fullname = os.path)
因为module name中出现了dot,所以python会对每个identifier进行分别处理,他会现在sys.modules中找os,如果找到,ok,继续import path。在准备import path时,实际使用的是os.path这个fullname,而不是简单的identifier。假设os.path还没有载入(在sys.modules中没有找到),那么他会查找能够找到path的finder,如果这个finder能够找到os.path,那么返回一个loader,该loader会被调用,来载入module,如果失败,则抛出ImportError异常。
由于os、path都是module,所以如果不做特殊处理,Python会报
查看os中的代码可以知道,os在import path后,将其添加到sys.modules中,Traceback (most recent call last): File "", line 1, in <module> ImportError: No module named path
# os.py import path # persudo code sys.modules['os.path'] = path
这样,当第二次python试图导入path时,将会直接在sys.modules中找到os.path,从而避免了ImportError。
我们要做的就是,在导入第一个parent module时,手动导入submodule,并且将submodule添加到sys.modules中。submodule必须由parent module预先添加到sys.modules中,一方面是为了防止ImportError,另一方面是为了submodule还能够被部分独立地重用。
考虑我们有3个module,分别是a, b, c,前一个是后一个Parent。所以可以这么实现,
优点:简单,不用以目录形式组织module hierachy# a.py import b import sys sys.modules['a.b'] = b sys.modules['a.b.c'] = b.c # b.py import c import sys sys.modules['b.c'] = c
缺点:复杂,需要手动将submodule加入到sys.modules
Package Hierachy
TODO:
Reference:
[1] Python 2.7 documentation - keyword sys.modules
[2] New Import Hooks - Specification part 1: The Importer Protocol