脚本与模块
这里有一个解释。简短的版本是,直接运行Python文件与从其他地方导入该文件之间存在很大差异。仅仅知道文件所在的目录并不能确定Python认为它所在的包。此外,这取决于如何将文件加载到Python中(通过运行或导入)。
有两种方法可以加载 Python 文件:作为顶级脚本,或作为模块。如果直接执行文件,例如通过在命令行上键入内容,则会将文件作为顶级脚本加载。当在某个其他文件中遇到语句时,它将作为模块加载。一次只能有一个顶级脚本;顶级脚本是您为开始操作而运行的 Python 文件。python myfile.py
import
命名
加载文件时,会为其指定一个名称(存储在其属性中)。__name__
- 如果它作为顶级脚本加载,则其名称为 。
__main__
- 如果它作为模块加载,则其名称为 [ 文件名,前面是它所属的任何包/子包的名称,用点分隔 ],例如 。
package.subpackage1.moduleX
但请注意,如果您使用类似的东西从 shell 命令行加载为模块,则仍将是 。moduleX
python -m package.subpackage1.moduleX
__name__
__main__
例如,在您的示例中:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
如果导入(注意:导入,不直接执行),则其名称将为 。如果导入 ,则其名称将为 。但是,如果直接从命令行运行,则其名称将为 ,如果直接从命令行运行,则其名称将为 。当模块作为顶级脚本运行时,它将丢失其正常名称,而其名称为 。moduleX
package.subpackage1.moduleX
moduleA
package.moduleA
moduleX
__main__
moduleA
__main__
__main__
访问模块时,不要通过其包含的包
还有一个额外的问题:模块的名称取决于它是从它所在的目录中“直接”导入的还是通过包导入的。这只有在目录中运行Python并尝试在同一目录(或其子目录)中导入文件时才会有所不同。例如,如果您在目录中启动Python解释器,然后执行,则 的名称将只是 ,而不是 。这是因为当以交互方式输入解释器时,Python会将当前目录添加到其搜索路径中;如果它在当前目录中找到要导入的模块,它将不知道该目录是包的一部分,并且包信息不会成为模块名称的一部分。package/subpackage1
import moduleX
moduleX
moduleX
package.subpackage1.moduleX
一个特殊情况是,如果您以交互方式运行解释器(例如,只需键入并开始动态输入Python代码)。在本例中,该交互式会话的名称为 。python
__main__
现在,这是错误消息的关键:如果模块的名称没有点,则不将其视为包的一部分。文件实际位于磁盘上的位置并不重要。重要的是它的名字是什么,它的名字取决于你如何加载它。
现在看看您在问题中包含的报价:
相对导入使用模块的 name 属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为“main”),则相对导入会被解析,就好像模块是顶级模块一样,而不管模块在文件系统上的实际位置如何。
相对进口...
相对导入使用模块的名称来确定它在包中的位置。当您使用相对导入(如 )时,这些点表示在包层次结构中增加一些级别。例如,如果当前模块的名称是 ,则表示 。要使 a 正常工作,模块的名称必须至少具有与语句中相同的点数。from .. import foo
package.subpackage1.moduleX
..moduleA
package.moduleA
from .. import
import
...仅在包中是相对的
但是,如果模块的名称是 ,则不将其视为在包中。它的名称没有点,因此您不能在其中使用语句。如果尝试这样做,则会收到“在非包中相对导入”错误。__main__
from .. import
脚本无法导入相对
您可能所做的是尝试从命令行运行或类似操作。执行此操作时,其名称设置为 ,这意味着其中的相对导入将失败,因为它的名称不会显示它位于包中。请注意,如果您从模块所在的同一目录运行Python,然后尝试导入该模块,也会发生这种情况,因为如上所述,Python会“过早”在当前目录中找到该模块,而没有意识到它是包的一部分。moduleX
__main__
另请记住,当您运行交互式解释器时,该交互式会话的“名称”始终为 。因此,您无法直接从交互式会话执行相对导入。相对导入仅用于模块文件。__main__
两种解决方案:
-
如果你真的想直接运行,但你仍然希望它被认为是软件包的一部分,你可以做。告诉 Python 将其作为模块加载,而不是作为顶级脚本加载。moduleX
python -m package.subpackage1.moduleX
-m
-
或者也许你实际上并不想运行,你只是想运行一些其他脚本,比如说,在里面使用函数。如果是这种情况,请放在其他位置 ( 而不是在目录中 ) 并运行它。如果你在里面做这样的事情,它会正常工作。moduleX
myfile.py
moduleX
myfile.py
package
myfile.py
from package.moduleA import spam
笔记
-
对于这两种解决方案中的任何一种,必须可以从 Python 模块搜索路径 () 访问包目录(在您的示例中)。如果不是,您将根本无法可靠地使用包中的任何内容。package
sys.path
-
从Python 2.6开始,用于包解析目的的模块的“名称”不仅由其属性决定,还由属性决定。这就是为什么我避免使用显式符号来引用模块的“名称”。由于Python 2.6,模块的“名称”是有效的,或者只是如果是。__name__
__package__
__name__
__package__ + '.' + __name__
__name__
__package__
None