gpt4 book ai didi

Python 3 模块和包相对导入不起作用?

转载 作者:太空宇宙 更新时间:2023-11-04 03:19:35 25 4
gpt4 key购买 nike

我在构建项目结构时遇到了一些困难。
这是我的项目目录结构:

MusicDownloader/
__init__.py
main.py
util.py
chart/
__init__.py
chart_crawler.py
test/
__init__.py
test_chart_crawler.py
这些是代码:
1.main.py
from chart.chart_crawler import MelonChartCrawler

crawler = MelonChartCrawler()
2.test_chart_crawler.py
from ..chart.chart_crawler import MelonChartCrawler

def test_melon_chart_crawler():
crawler = MelonChartCrawler()
3.chart_crawler.py
import sys
sys.path.append("/Users/Chois/Desktop/Programming/Project/WebScrape/MusicDownloader")
from .. import util

class MelonChartCrawler:
def __init__(self):
pass
4.util.py
def hi():
print("hi")
在 MusicDownloader 中,当我通过 python main.py 执行 main.py 时,它显示错误:
  File "main.py", line 1, in <module>
from chart.chart_crawler import MelonChartCrawler
File "/Users/Chois/Desktop/Programming/Project/WebScrape/MusicDownloader/chart/chart_crawler.py", line 4, in <module>
from .. import util
ValueError: attempted relative import beyond top-level package
但是当我通过 py.test test_chart_crawler.py 在测试目录中执行我的测试代码时, 有用
当我第一次面对绝对的、相对的导入时,它看起来非常简单和直观。但它现在让我发疯。需要你的帮助。谢谢

最佳答案

第一个问题是MusicDownloader不是一个包。添加 __init__.pyMusicDownloader连同 main.py和你的相对进口..chart应该管用。相对导入只在包内起作用,所以你不能 ..到非包文件夹。

编辑我的帖子,为您的答案编辑提供更准确的答案。

都是关于 __name__ .相对进口使用 __name__使用它们的模块和from .(.)部分以形成要导入的完整包/模块名称。简述进口商的__name__from 连接部分,用点表示要忽略/删除的名称组件的数量,即:
__name__='packageA.packageB.moduleA'包含以下行的文件:from .moduleB import something ,导致进口的综合值(value)packageA.packageB.moduleB , 大概是 from packageA.packageB.moduleB import something (但不是绝对导入,因为如果直接这样输入)。
__name__='packageA.packageB.moduleA'包含以下行的文件:from ..moduleC import something ,导致进口的综合值(value)packageA.moduleC , 大概是 from packageA.moduleC import something (但不是绝对导入,因为如果直接这样输入)。

这里如果是 moduleB(C)packageB(C)没关系。重要的是我们仍然拥有 packageA在这两种情况下,作为相对导入的“ anchor ”的部分。如果没有packageA部分,相对导入将无法解决,我们会收到类似“尝试相对导入超出顶级包”的错误。

这里还要注意一点,当一个模块运行时,它会得到一个特殊的 __name__ __main__ 的值,这显然会阻止它解决任何相关的导入。

现在关于您的情况,请尝试添加 print(__name__)作为每个文件的第一行,在不同的场景中运行你的文件,看看输出是如何变化的。

也就是说,如果你直接运行你的 main.py,你会得到:

__main__
chart.chart_crawler
Traceback (most recent call last):
File "D:\MusicDownloader\main.py", line 2, in <module>
from chart.chart_crawler import MelonChartCrawler
File "D:\MusicDownloader\chart\chart_crawler.py", line 2, in <module>
from .. import util
ValueError: Attempted relative import beyond toplevel package

这里发生的事情是... main.py不知道 MusicDownloader作为一个包(即使在之前添加 __init__.py 的编辑之后)。在您的 chart_crawler.py : __name__='chart.chart_crawler'当使用 from .. 运行相对导入时如上所述,package 的组合值需要删除两个部分(每个点一个),因此结果将变为 ''因为只有两部分,没有封闭包装。这导致异常。

当你导入一个模块时,它里面的代码会运行,所以它几乎和执行它一样,但是没有 __name__成为 __main__和封闭的包裹,如果有的话,被“注意到”。

因此,解决方案是导入 main.py作为 MusicDownloader 的一部分包裹。要完成上述操作,请创建一个模块,例如命名为 launcher.pyMusicDownloader 处于同一层级使用以下代码的文件夹(靠近它,而不是靠近 main.py ):
print(__name__)
from MusicDownloader import main

现在运行 launcher.py并查看变化。输出:
__main__
MusicDownloader.main
MusicDownloader.chart.chart_crawler
MusicDownloader.util

这里 __main____name__里面 launcher.py .内部 chart_crawler.py : __name__='MusicDownloader.chart.chart_crawler'当使用 from .. 运行相对导入时如上所述,package 的组合值需要删除两个部分(每个点一个),因此结果将变为 'MusicDownloader'导入成为 from MusicDownloader import util .正如我们在下一行看到的 util.py成功导入它会打印它的 __name__='MusicDownloader.util' .

差不多就是这样——“这就是 __name__”。

附言没有提到的一件事是为什么带有 test 的部分包工作。它不是以普通方式启动的,您使用了一些额外的模块/程序来启动它,并且它可能以某种方式导入它,所以它起作用了。要理解这一点,最好看看该程序是如何工作的。

official docs 中有注释:

Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.

关于Python 3 模块和包相对导入不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35110653/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com