python模块与包加载机制

模块的搜索路径:

When a module named spam is imported, the interpreter searches for a file named spam.py in the current directory, and then in the list of directories specified by the environment variable PYTHONPATH. This has the same syntax as the shell variable PATH, that is, a list of directory names. When PYTHONPATH is not set, or when the file is not found there, the search continues in an installation-dependent default path; on Unix, this is usually .:/usr/local/lib/python.

导入一个叫 spam 的模块时,解释器先在当前目录中搜索名为 spam.py 的文件,然后在环境变量 PYTHONPATH 表示的目录列表中搜索,。如果 PYTHONPATH没有设置,或者文件没有找到,接下来搜索安装目录,在UNIX中,通常是 .:/usr/local/lib/python。

当前目录-》PYTHONPATH->python安装默认目录

Actually, modules are searched in the list of directories given by the variable sys.path which is initialized from the directory containing the input script (or the current directory), PYTHONPATH and the installation-dependent default. This allows Python programs that know what they're doing to modify or replace the module search path. Note that because the directory containing the script being run is on the search path, it is important that the script not have the same name as a standard module, or Python will attempt to load the script as a module when that module is imported. This will generally be an error. See section 6.2, ``Standard Modules,'' for more information.

实际上,解释器由 sys.path 变量指定的路径目录搜索模块,该变量初始化时默认包含了输入脚本(或者当前目录), PYTHONPATH 和安装目录。这样就允许Python程序(原文如此,programs;我猜想应该是“programer”,程序员--译者)了解如何修改或替换模块搜索目录。需要注意的是由于这些目录中包含有搜索路径中运行的脚本,所以这些脚本不应该和标准模块重名,否则在导入模块时Python会尝试把这些脚本当作模块来加载。这通常会引发一个错误。请参见 6.2节“标准模块”以了解更多的信息。

转自:Python手册Python Tutorial

除了使用import sys这样的方式加载module之外,

还可以使用:

import sys 
sys.path.append('f:\pythonworks') 

sys.path.insert(0,'f:\c‘)
 

1)关于module
通常模块为一个文件,直接使用import来导入就好了。

可以作为module的文件类型有".py"、".pyo"、".pyc"、".pyd"、".so"、".dll"。

2)关于package
通常包总是一个目录,可以使用import导入包,

或者from + import来导入包中的部分模块。

包目录下为首的一个文件便是 __init__.py。

然后是一些模块文件和子目录,假如子目录中也有 __init__.py 那么它就是这个包的子包了

使用import spam 语句就可以将这个文件(spam)作为模块导入。

默认的检索路径为执行python的当前路径和sys.path路径

系统在导入模块时,要做以下三件事: 
1. 为源代码文件中定义的对象创建一个命名空间,通过这个命名空间可以访问到模块中定义的函数及变量。

2. 在新创建的命名空间里执行源代码文件。

3. 创建一个名为源代码文件的对象,该对象引用模块的命名空间,这样就可以通过这个对象访问模块中的函数及变量,如:  

 import spam           导入并运行模块 spam
 print spam.a          访问模块 spam 的属性
 spam.foo()
 c = spam.bar()
 ...

用逗号分割模块名称就可以同时导入多个模块: 
import socket, os, regex模块导入时可以使用 as 关键字来改变模块的引用对象名字:

import os as system
import socket as net, thread as threads
system.chdir("..")
net.gethostname()

使用from语句可以将模块中的对象直接导入到当前的名字空间. from语句不创建一个到模块名字空间的引用对象,而是把被导入模块的一个或多个对象直接放入当前的名字空间:

from socket import gethostname
                               gethostname放如当前名字空间
print gethostname()            直接调用
socket.gethostname()           引发异常NameError: socket

from语句支持逗号分割的对象,也可以使用星号(*)代表模块中除下划线开头的所有对象: 

from socket import gethostname, socket
from socket import *   载入所有对象到当前名字空间

import 语句可以在程序的任何位置使用,你可以在程序中多次导入同一个模块,但模块中的代码*仅仅*在该模块被首次导入时执行。后面的import语句只是简单的创建一个到模块名字空间的引用而已。sys.modules字典中保存着所有被导入模块的模块名到模块对象的映射。这个字典用来决定是否需要使用import语句来导入一个模块的最新拷贝. 
from module import * 语句只能用于一个模块的最顶层.*特别注意*:由于存在作用域冲突,不允许在函数中使用from 语句。 
每个模块都拥有 __name__ 属性,它是一个内容为模块名字的字符串。最顶层的模块名称是 __main__ .命令行或是交互模式下程序都运行在__main__ 模块内部. 利用__name__属性,我们可以让同一个程序在不同的场合(单独执行或被导入)具有不同的行为,象下面这样做:

检查是单独执行还是被导入

if __name__ == '__main__':
      # Yes
      statements
else:
      # No (可能被作为模块导入)
      statements 

模块搜索路径
导入模块时,解释器会搜索sys.path列表,这个列表中保存着一系列目录。一个典型的sys.path 列表的值:

Linux:
['''/usr/local/lib/python2.0',
     '/usr/local/lib/python2.0/plat-sunos5',
     '/usr/local/lib/python2.0/lib-tk',
     '/usr/local/lib/python2.0/lib-dynload',
     '/usr/local/lib/python2.0/site-packages']
Windows:
['''C:\WINDOWS\system32\python24.zip''C:\Documents and Settings\weizhong''C:\Python24\DLLs''C:\Python24\lib''C:\Python24\lib\plat-win''C:\Python24\lib\lib-tk''C:\Python24\Lib\site-packages\pythonwin''C:\Python24''C:\Python24\lib\site-packages''C:\Python24\lib\site-packages\win32''C:\Python24\lib\site-packages\win32\lib''C:\Python24\lib\site-packages\wx-2.6-msw-unicode']

空字符串 代表当前目录. 要加入新的搜索路径,只需要将这个路径加入到这个列表. 

二包
多个关系密切的模块应该组织成一个包,以便于维护和使用。这项技术能有效避免名字空间冲突。创建一个名字为包名字的文件夹并在该文件夹下创建一个__init__.py 文件就定义了一个包。你可以根据需要在该文件夹下存放资源文件、已编译扩展及子包。举例来说,一个包可能有以下结构:

Graphics/
      __init__.py
      Primitive/
         __init__.py
         lines.py
         fill.py
         text.py
         ...
      Graph2d/
         __init__.py
         plot2d.py
         ...
      Graph3d/
         __init__.py
         plot3d.py
         ...
      Formats/
         __init__.py
         gif.py
         png.py
         tiff.py
         jpeg.py

import语句使用以下几种方式导入包中的模块: 
* import Graphics.Primitive.fill 导入模块Graphics.Primitive.fill,只能以全名访问模块属性,例如Graphics.Primitive.fill.floodfill(img,x,y,color). 
* from Graphics.Primitive import fill 导入模块fill ,只能以 fill.属性名这种方式访问模块属性,例如fill.floodfill(img,x,y,color). 
* from Graphics.Primitive.fill import floodfill 导入模块fill ,并将函数floodfill放入当前名称空间,直接访问被导入的属性,例如 floodfill(img,x,y,color).


无论一个包的哪个部分被导入, 在文件__init__.py中的代码都会运行.这个文件的内容允许为空,不过通常情况下它用来存放包的初始化代码。导入过程遇到的所有 __init__.py文件都被运行.因此 import Graphics.Primitive.fill 语句会顺序运行 Graphics 和 Primitive 文件夹下的__init__.py文件.


下边这个语句具有歧义: 
from Graphics.Primitive import * 
这个语句的原意图是想将Graphics.Primitive包下的所有模块导入到当前的名称空间.然而,由于不同平台间文件名规则不同(比如大小写敏感问题), Python不能正确判定哪些模块要被导入.这个语句只会顺序运行 Graphics 和Primitive 文件夹下的__init__.py文件. 要解决这个问题,应该在Primitive文件夹下面的__init__.py中定义一个名字all的列表,例如: 
# Graphics/Primitive/__init__.py
__all__ = ["lines","text","fill",...]

这样,上边的语句就可以导入列表中所有模块.


下面这个语句只会执行Graphics目录下的__init__.py文件,而不会导入任何模块: 
import Graphics
Graphics.Primitive.fill.floodfill(img,x,y,color)  # 失败!

不过既然 import Graphics 语句会运行 Graphics 目录下的 __init__..py文件,我们就可以采取下面的手段来解决这个问题: 
# Graphics/__init__.py
import Primitive, Graph2d, Graph3d

# Graphics/Primitive/__init__.py
import lines, fill, text, ...

这样import Graphics语句就可以导入所有的子模块(只能用全名来访问这些模块的属性).

refer to:http://blog.csdn.net/appleheshuang/article/details/7602499

原文地址:https://www.cnblogs.com/youxin/p/3746372.html