为什么 __path__[0] 在常规包中是唯一的索引搜索?

Why __path__[0] in reqular packages is the only index searched?

当我在 Python 中创建一个常规包时,我得到一个带有 __path__ 方法的对象,根据 Python 文档,它被认为是一种特殊类型的模块。我的问题是为什么在 pack.__path__ 列表中只搜索第一个项目而其他项目被省略,为什么它是一个列表而不是一个普通的字符串,因为其他项目没有被扫描?

示例: 假设我们有一个名为 C:\code 的目录,其中包含一个名为 pkg 的包。和另一个包含 spam.py 的路径:

    C\
     pkg\                #Regular package
         .__init__.py
     another\ 
         spam.py  #print('spam')          

>>> import pkg

>>> pkg.__path__    #Only __path__[0] searched
   ['C:\code\pkg']    

>>> pkg.path.append(r'C:\another')

>>> pkg.__path__ 
   ['C:\code\pkg', 'C:\another']   # __path__[1] omitted

>>> import pkg.spam                  # Fails! 
   ImportError:... 

>>> pkg.__path__.pop(0)              # Works!
>>> pkg.spam
    spam

所以我想知道为什么 Python 只遍历 __path__[0] 而不是像在 3.X 中那样遍历整个列表来命名空间包?如果没有完全遍历,将 __path__ 作为列表是没有意义的。我知道常规包与名称空间包不同,但为什么要在这里列出一个列表并只允许单一搜索路径呢!但是,Python 3.3 遍历了整个列表,在某些形式下,它通过在 __path__ 属性中为常规包添加目录来模拟命名空间包的行为。

__path__[0] 不仅是 Python 在包中搜索相对导入的路径。至少这是我在 Cpython 2.7 和 Python 3.3 中测试的真实行为。 Python 使用相对导入时从左到右遍历 __path__[0]__path__[0] 列表的作用与sys.path 的作用相同。它们都包含通向包或模块的系统路径(目录前缀),Python 在使用任何导入语句时自动收集(例如 importfrom

实际上,您可以使用 pkgutil.extend_path 函数扩展 __path__[0],让相关包导入,从包目录以外的不同目录导入。例如:

C:
  \dir0        #container directory
     \pkg      #package 
       __init__.py 
       spam.py
    \dir1 
        ham.py
>>> __path__ 
   ['C:\dir0'] 

假设__init__.py文件(初始化文件)包含以下代码:

__path__.append(r'C:\dir1')    #Or pkgutil.extend_path function
from . import spam,ham          #Relative import(relative to pkg dir)  

spam 将从包目录导入,因为这是 2.X 和 3.X 中的 相对导入 。但是,请注意 ham 也将如何成功导入,即使它不像 spam 模块那样存在于包的主目录中,它仍然可以作为模块的目录导入 ham 在包 pkg__path__ 列表中。

由于 ham 是自动导入的,没有任何错误,这表明 Python 从左到右遍历包的 __path__ 列表。

不过,您可以将 __path__ 视为 sys.path,但 __path__ 仅用于 packages.Python 2.X 搜索中的导入 __path__,在 sys.path 之前。那是 相对的,然后是绝对的 。 Python 3.X 将此更改为, 仅绝对 ,除非您在 from 导入语句中使用点,from . import ...,Python 3.X 将始终搜索模块搜索路径。