![](/img/trans.png)
[英]Importing relative package modules in python doesn't work in the following format?
[英]Python 3 modules and package relative import doesn't work?
我在構建我的項目結構時遇到了一些困難。
這是我的項目目錄結構:
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
在 test 目錄中執行我的測試代碼時,它可以工作
當我第一次面對絕對導入和相對導入時,這似乎非常簡單和直觀。 但它現在讓我發瘋。 需要你的幫助。 謝謝
第一個問題是MusicDownloader
不是一個包。 添加__init__.py
到MusicDownloader
沿main.py
和你的相對進口..chart
應該工作。 相對導入僅在包內有效,因此您不能..
到非包文件夾。
編輯我的帖子,為您的答案編輯提供更准確的答案。
這都是關於__name__
。 相對導入使用__name__
所在模塊的__name__
和from .(.)
部分來形成要導入的完整包/模塊名稱。 用簡單的術語解釋進口商的__name__
與from
部分連接,點顯示要忽略/刪除的名稱組件的數量,即:
__name__='packageA.packageB.moduleA'
包含行的文件: from .moduleB import something
,導致 import packageA.packageB.moduleB
組合值,所以大致from packageA.packageB.moduleB import something
(但不是絕對導入,因為它如果直接輸入這樣的話)。
__name__='packageA.packageB.moduleA'
包含行的文件: from ..moduleC import something
,導致 import packageA.moduleC
組合值,所以大致from packageA.moduleC import something
(但不是絕對導入,如果直接打字)。
這里是moduleB(C)
還是moduleB(C)
packageB(C)
並不重要。 重要的是我們仍然有packageA
部分,它在兩種情況下都可以作為相對導入的“錨點”。 如果沒有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 ..
運行相對導入時,包的組合值將需要刪除兩部分(每個點一個),如上所述,因此結果將變為''
因為只有兩部分,沒有封閉的包裹。 這導致異常。
當你導入一個模塊時,它里面的代碼會運行,所以它和執行它幾乎一樣,但沒有__name__
變成__main__
和封閉的包,如果有的話,被“注意到”。
因此,解決方案是將main.py
作為MusicDownloader
包的一部分導入。 要完成上述操作,請使用以下代碼在與MusicDownloader
文件夾(靠近它,而不是靠近main.py
內部)相同的層次結構級別上創建一個名為launcher.py
的模塊:
print(__name__)
from MusicDownloader import main
現在運行launcher.py
並查看更改。 輸出:
__main__
MusicDownloader.main
MusicDownloader.chart.chart_crawler
MusicDownloader.util
這里__main__
是launcher.py
的__name__
。 在chart_crawler.py
: __name__='MusicDownloader.chart.chart_crawler'
並且當使用from ..
運行相對導入時, package 的組合值將需要刪除兩部分(每個點一個),如上所述,因此結果將變為'MusicDownloader'
與 import 變成from MusicDownloader import util
。 正如我們在下一行看到的,當util.py
成功導入時,它會打印其__name__='MusicDownloader.util'
。
所以__name__
就是這樣 - “這都是關於__name__
”。
PS 沒有提到的一件事是為什么帶有test
包的部分有效。 它沒有以常見的方式啟動,您使用了一些額外的模塊/程序來啟動它,並且它可能以某種方式導入它,所以它起作用了。 要理解這一點,最好看看該程序是如何工作的。
官方文檔中有一個注釋:
請注意,相對導入基於當前模塊的名稱。 由於主模塊的名稱始終為“__main__”,因此用作 Python 應用程序主模塊的模塊必須始終使用絕對導入。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.