近日在尝试引用其他文件的代码时,遇到了错误: ImportError: attempted relative import with no known parent package.
问题大致是这样的:我想在 code2.py
中引用 code1.py
的函数,如 from ..folder1.code1 import xxx
,运行 code2.py
时出现错误。
root
├── folder1
│ └── code1.py
├── folder2
│ └── code2.py
└── main.py
如果你要在 code2.py
中引用 code1.py
的函数,那么可以:
main.py
中调用,运行 main.py
code2.py
中增加 root
的位置到搜索路径 sys.path.append
, 代码使用 from folder1.code1 import xxx
-m
选项运行: python -m root.folder2.code2
,代码可以使用 from folder1.code1 import xxx
或 from ..folder1.code1 import xxx
[我认为这是最优解!]如果对导入的概念不是很理解的话,可能会遇到:
首先明确两种导入方法:
from xxx import yyy
则是从已知的模块导入from .xxx import yyy
,根据从当前文件的相对路径导入。具体可参考官方文档 the-module-search-path
仅适用于模块(文件夹)或脚本(文件)存在于搜索路径中,导入时,Python 解释器会首先搜索内置模块,如果没有,则去以下三个位置搜索:
PYTHONPATH
指定的目录可以查看 sys.path
,显然,当前运行脚本所在的文件夹被放在了搜索路径的首位,因此该文件夹下的所有内容均可被引入。
import sys
print(sys.path)
# ['/.../path-to-this-folder', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/home/thor/.local/lib/python3.10/site-packages', '/usr/local/lib/python3.10/dist-packages', '/usr/lib/python3/dist-packages']
要解决开头提出的问题,即引入其他文件夹下的内容,可以把 root 的位置添加到搜索路径中:(好吧,这样很不优雅……)
import sys
sys.path.join("/path/to/root") # 用绝对路径,需要从根目录开始
sys.path.join("..") # 用相对路径,但是命令行当前位置不能出错
from folder1.code1 import xxx
可以参考这段代码[1]:
if __package__:
from .. import config
else:
sys.path.append(os.dirname(__file__) + '/..')
import config
具体可参考官方文档 packages
需要明确的是,这种方法只适用于 package 内部!
当你把 code2.py
作为脚本运行时,即 python code2.py
,此时 python 并不会认为它属于某一个 package, 即使存在 __init__.py
。可以 print(__package__)
进行验证,作为脚本运行时为 None
,否则则应该为 xxx.yyy
的形式[1:1]。
(网络上有很多地方都说添加 __init__.py
就可以解决问题,但事实是并不会 ,在我的测试中,在本文提到的所有的解决方法中,添加 __init__.py
与否似乎不会带来什么影响。)
因此,开头描述的问题中,要使用相对导入的形式在 code2.py
中引用 code1.py
的代码,必须使用:
python -m root.folder1.code1
.py
后缀。python -m folder1.code1
,此时把 folder1 及其内部当作一个完整的 package, 无法引用到以外的内容,会遇到 ImportError: attempted relative import beyond top-level package除了命令行调用时进行调整,在脚本中 import 也是一样的道理:
newroot
├── root
│ ├── folder1
│ │ └── code1.py
│ ├── folder2
│ │ └── code2.py
│ └── main.py
└── upper_main.py
upper_main.py
中添加 from root.folder2 import code2
并运行时,它会把 root
当作一个包,此时code2.py
中的 from ..folder1.code1 import xxx
可以正常执行main.py
中添加 import folder2.code2
并运行时,它会把 folder2
当作一个包,此时 code2.py
中的 from .xx import
可以正常执行,而 from ..folder1.code1 import xxx
会遇到 ImportError: attempted relative import beyond top-level package.说明:
code2.py
中有 from folder1 import code1
这种做法,没有测试过其适用条件,不过模块内部感觉使用相对引用比较好。其他参考资料:
手机扫一扫
移动阅读更方便
你可能感兴趣的文章