假设我有以下文件,
pkg/
pkg/__init__.py
pkg/main.py # import string
pkg/string.py # print("Package's string module imported")
现在,如果我运行main.py
,则会显示"Package's string module imported"
。
这是有道理的,它可以按照link中的这个陈述运作:
“它将首先查看软件包的目录”
假设我稍微修改了文件结构(添加了一个核心目录):
pkg/
pkg/__init__.py
plg/core/__init__.py
pkg/core/main.py # import string
pkg/string.py # print("Package's string module imported")
现在,如果我运行python core/main.py
,它会加载内置的string
模块。
在第二种情况下,如果必须遵守声明“它将首先查看包的目录”,它不应该加载本地string.py
,因为{{1是“包目录”?
我对“包目录”一词的含义是具体 集合的根文件夹包含pkg
的文件夹。所以在这种情况下, pkg 是“包目录”。它适用于__init__.py
以及main.py
等子目录中的文件,因为它是此“包”的一部分。
技术上是否正确?
PS:代码片段中core/main.py
之后的内容是文件的实际内容(没有前导空格)。
答案 0 :(得分:2)
包是具有__init__.py
文件的目录,是,并且在模块搜索路径上作为模块加载。因此,pkg
只是一个包,您可以将其导入并视为包,如果父目录位于模块搜索路径。
但是通过将pkg/core/main.py
文件作为脚本运行,Python将pkg/core
目录添加到模块搜索路径,而不是pkg
的父目录。您现在在模块搜索路径上有__init__.py
个文件,但这不是定义包的内容。您只有一个__main__
模块,与其他任何东西都没有包关系,并且您不能依赖隐式相对导入。
您有三种选择:
不要将包内的文件作为脚本运行。将您的包的脚本文件放在之外,然后根据需要导入您的包。您可以将 next 放到pkg
目录中,或者确保pkg
目录首先安装到模块搜索路径上已有的目录中,或者让脚本计算出来添加到sys.path
的正确路径。
使用-m
command line switch运行模块,就好像它是一个脚本一样。如果您使用python -m pkg.core
,Python将查找__main__.py
文件并将其作为脚本运行。 -m
开关将当前工作目录添加到模块搜索路径,因此当您在正确的工作目录中时,您可以使用该命令,一切都会正常工作。或者将您的软件包安装在模块搜索路径上的目录中。
让您的脚本将正确的目录添加到模块搜索路径(基于os.path.absolute(__file__)
以获取当前文件的路径)。考虑到您的脚本始终命名为__main__
,导入pkg.core.main
将添加第二个独立的模块对象;你有两个独立的命名空间。
我还强烈反对使用隐式相对导入的建议。您可以通过添加具有相同名称的嵌套包或模块轻松地屏蔽顶级模块和包。如果您尝试在pkg/time.py
包中使用time
,则会在标准库import time
模块之前找到pkg
。相反,使用显式相对模块引用的Python 3模型;将from __future__ import absolute_import
添加到您的所有文件中,然后使用from . import <name>
明确指出从哪里导入模块。