[譯][python]ImportError:attempted relative import with no known parent package
原部落格連結https://blog.csdn.net/nigelyq/article/details/78930330
前言
在這篇文章中,我將會解析 ImportError: attempted relative import with no known parent package
這個異常的原因。當你在執行的python指令碼。使用了相對引用方式 (類似import ..module
) 去引用包時,可能會出現這個異常。
讓我們來看看發生這個異常的例子。
問題
假設你有以下目錄結構:
project ├── config.py └── package ├── __init__.py └── demo.py
config.py
中包含一些應該在 demo.py
中使用的變數
- project/config.py
count = 5
- project/package/demo.py
from .. import config
print("The value of config.count is {0}".format(config.count))
當我們嘗試執行demo.py
時,會遇到以下錯誤:
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直譯器丟擲了沒有父級包的異常。為什麼?
讓我們看看python直譯器是如何解析相關模組。從 PEP 328 中,我們找到了關於 the relative imports
(相對引用)的介紹:
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.相對匯入通過使用模組的 __name__ 屬性來確定模組在包層次結構中的位置。如果該模組的名稱不包含任何包資訊(例如,它被設定為 __main__ ),那麼相對引用會認為這個模組就是頂級模組,而不管模組在檔案系統上的實際位置。
換句話說,解決模組的演算法是基於__name__
和__package__
變數的值。大部分時候,這些變數不包含任何包資訊 —- 比如:當 __name__
= __main__
和 __package__
= None
時,python直譯器不知道模組所屬的包。在這種情況下,相對引用會認為這個模組就是頂級模組,而不管模組在檔案系統上的實際位置。
為了演示這個原理,我們來更新一下程式碼:
- project/config.py
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
count = 5
- project/package/demo.py
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
- toplevel/main.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