为什么 __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 在使用任何导入语句时自动收集(例如 import
、from
)
实际上,您可以使用 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 将始终搜索模块搜索路径。
当我在 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 在使用任何导入语句时自动收集(例如 import
、from
)
实际上,您可以使用 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 将始终搜索模块搜索路径。