iT邦幫忙

0

Python from import的路徑問題

jojo 2022-08-02 17:52:279194 瀏覽
  • 分享至 

  • xImage

以下是我假設的路徑
package
├── init.py
├── subpackage1
│ ├── init.py
│ ├── moduleX.py
│ └── moduleY.py
├── subpackage2
│ ├── init.py
│ └── moduleZ.py
└── moduleA.py
路徑參考

今天我在moduelX.py要import moduleZ.py裡的egg function
我出現了以下狀況:

  • from package.subpackage2.moduleZ import egg 出現 No module named 'package'
  • from ..subpackage2.moduleZ import egg 出現 attempted relative import with no known parent package

我有嘗試用sys.path.append把目錄的路徑放進去,是可以解決問題的。

但我想知道如果不透過sys.path.append的方式,為甚麼會出現錯誤/images/emoticon/emoticon17.gif
一直找不到解決方式,請求大大解惑,謝謝。
參考的文章

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

4
akitect
iT邦新手 5 級 ‧ 2022-08-02 21:43:35
最佳解答

Python Documentation

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.

相對 import 的運作是以目前的模組名稱為依據。因為主模組的名稱永遠是 "__main__",所以如果一個模組預期被用作 Python 應用程式的主模組,那它必須永遠使用絕對 import。

以及 PEP 328

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.

相對 import 通過使用模組的 __name__ 屬性來確定模組在包層次結構中的位置。如果該模組的名稱不包含任何包資訊(例如,它被設定為 __main__),那麼相對 import 會認為這個模組就是頂層模組,而不管模組在檔案系統上的實際位置。

意思是,當你直接運行 moduleX.py 的時候,moduleX.py 是程式的入口點 (Entry point),因此 __name__ == "__main__"moduleX.py 被認為是頂層 module,上面再沒有其他的 module。


解決方案一

建立 root_directoryroot.py,從 root.py 調用 moduleX.py,令 root.py 成為頂層

root_directory 
├── root.py 
└── package 
	├── __init__.py 
	├── subpackage1
	|	├── __init__.py
	|	└── moduleX.py
	└── subpackage2
		├── __init__.py
		└── moduleZ.py
# root.py
from package.subpackage1 import moduleX

# moduleX.py
from ..subpackage2.moduleZ import egg
egg()

# moduleZ.py
def egg():
    pass

解決方案二

package 
	├── subpackage1
	|	├── __init__.py
	|	└── moduleX.py
	└── subpackage2
		├── __init__.py
		└── moduleZ.py
# moduleX.py
from package.subpackage2.moduleZ import egg
egg()

# moduleZ.py
def egg():
    pass

moduleX.py 當成 module 來執行:

$ python -m package.subpackage1.moduleX

解決方案三

各式各樣的添加路徑


繼續深入研究方向:
__name____package__

分析過程:
https://stackoverflow.com/questions/16981921/relative-imports-in-python-3
https://stackoverflow.com/questions/30669474/beyond-top-level-package-error-in-relative-import

jojo iT邦新手 5 級 ‧ 2022-08-02 23:13:06 檢舉

原來是被當最頂層了!謝謝指教!!

我要發表回答

立即登入回答