当我在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__
没有完全遍历,那么将__path__
作为列表是没有意义的。我知道常规包与命名空间包不同,但是为什么在这里打扰列表并且只允许搜索路径!但是,Python 3.3遍历整个列表,在某些形式中,它通过在常规包的{{1}}属性中添加目录来模拟命名空间包的行为。
答案 0 :(得分:1)
__path__[0]
不仅是Python在包中搜索相对导入的路径。至少这是我在Cpython 2.7和Python 3.3中测试的真实行为。使用相对导入时,Python从左到右遍历__path__[0]
。 __path__[0]
列表所扮演的角色与sys.path
的角色相同。它们都包含系统路径(目录的前缀),它们通向一个包或一个模块,当使用任何import语句时,Python会自动收集该模块(例如import
,from
)
实际上,您可以使用__path__[0]
函数扩展pkgutil.extend_path
以使相对包导入,从包目录以外的其他目录导入。例如:
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
模块那样存在于包的主目录中,它仍然可以导入为模块的目录{{1在包ham
的{{1}}列表中。
由于__path__
是自动导入的,没有任何错误,这表明Python从左到右遍历包的pkg
列表。
但是,您可以将ham
视为__path__
,但__path__
仅用于包中的导入.Python 2.X在{{1}之前搜索sys.path
}}。这是相对 - 然后绝对。 Python 3.X将此更改为 absolute-only ,除非您使用__path__
import语句中的点__path__
,Python 3.X将始终搜索模块搜索路径。