在這篇文章中,我將會解析 ImportError: attempted relative import with no known parent package
這個異常的緣由。當你在運行的python腳本。使用了相對引用方式 (相似import ..module
) 去引用包時,可能會出現這個異常。python
讓咱們來看看發生這個異常的例子。算法
假設你有如下目錄結構:shell
project
├── config.py
└── package
├── __init__.py
└── demo.py
複製代碼
config.py
中包含一些應該在 demo.py
中使用的變量vim
count = 5
複製代碼
from .. import config
print("The value of config.count is {0}".format(config.count))
複製代碼
當咱們嘗試運行demo.py
時,會遇到如下錯誤:less
E:\project> python demos/demo.py
Traceback (most recent call last):
File "demos/demo.py", line 1, in <module>
from .. import config
ImportError: attempted relative import with no known parent package
複製代碼
python解釋器拋出了沒有父級包的異常。爲何?post
讓咱們看看python解釋器是如何解析相關模塊。從 PEP 328 中,咱們找到了關於 the relative imports
(相對引用)的介紹:spa
Relative imports use a module’s __name__ attribute to determine that module’s position in the package hierarchy. If the module’s name does not contain any package information (e.g. it is set to __main__ ) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.code
相對導入經過使用模塊的 __name__ 屬性來肯定模塊在包層次結構中的位置。若是該模塊的名稱不包含任何包信息(例如,它被設置爲 __main__ ),那麼相對引用會認爲這個模塊就是頂級模塊,而無論模塊在文件系統上的實際位置。orm
換句話說,解決模塊的算法是基於__name__
和__package__
變量的值。大部分時候,這些變量不包含任何包信息 ---- 好比:當 __name__
= __main__
和 __package__
= None
時,python解釋器不知道模塊所屬的包。在這種狀況下,相對引用會認爲這個模塊就是頂級模塊,而無論模塊在文件系統上的實際位置。get
爲了演示這個原理,咱們來更新一下代碼:
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
count = 5
複製代碼
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
from .. import config
print("The value of config.count is {0}".format(config.count))
複製代碼
再次嘗試運行一下,會獲得如下輸出:
E:\project> python demos/demo.py
__file__=demos/demo.py | __name__=__main__ | __package__=None
Traceback (most recent call last):
File "demos/demo.py", line 3, in <module>
from .. import config
ImportError: attempted relative import with no known parent package
複製代碼
正如咱們所看到的,python解釋器沒有關於模塊所屬的包的任何信息( __name__
= __main__
和 __package__
= None
),所以它拋出了找不到父級包的異常。
咱們經過在其中建立一個新的空 __init__.py
文件來將項目目錄轉換爲一個包。
咱們在項目目錄的父目錄中建立一個文件 main.py
toplevel
├── main.py
└── project
├── __init__.py
├── config.py
└── package
├── __init__.py
└── demo.py
複製代碼
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
import project.demos.demo
複製代碼
執行一下新的示例,輸出以下:
E:\toplevel>python main.py
__file__=main.py | __name__=__main__ | __package__=None
__file__=E:\toplevel\project\demos\demo.py | __name__=project.demos.demo | __package__=project.demos
__file__=E:\toplevel\project\config.py | __name__=project.config | __package__=project
The value of config.count is 5
複製代碼
在 main.py
中導入 project.demos.demo
會設置相對引用的包信息( __name__
和 __package__
變量)。如今,python解釋器能夠成功解析 project\demos\demo.py
中的相對引用了。
咱們經過在 project
文件夾中建立一個新的空 __init__.py
來將 project
目錄轉換爲一個包。
在 toplevel
目錄下經過 -m
參數來調用python解釋器,去執行 project.demos.demo
[1]
toplevel
└── project
├── __init__.py
├── config.py
└── package
├── __init__.py
└── demo.py
複製代碼
再次執行:
E:\toplevel>python -m project.demos.demo
__file__=E:\toplevel\project\demos\demo.py | __name__=__main__ | __package__=project.demos
__file__=E:\toplevel\project\config.py | __name__=project.config | __package__=project
The value of config.count is 5
複製代碼
運行該命令將自動設置包信息(__package__
變量)。如今,python解釋器能夠成功解析 project\ demos\demo.py
中的相對引用了(甚至認爲 __name __
= __ main__
)。
[1] 譯者注:注意使用 -m
參數的時候,後面指定的執行文件沒有 .py
後綴
import-error-relative-no-parent
注:轉載請保留下面的內容