[英]Python - ModuleNotFoundError: No module named
我是 Python 的新手,我在這個簡單的示例中遇到以下錯誤:
這是我的項目結構:
python_project
.
├── lib
│ ├── __init__.py
│ └── my_custom_lib.py
└── src
├── __init__.py
└── main.py
這是我執行src/main.py
文件時的錯誤:
☁ python_project python src/main.py
Traceback (most recent call last):
File "src/main.py", line 3, in <module>
from lib import my_custom_lib
ImportError: No module named lib
如果我將main.py
文件移動到根目錄,然后再次執行此文件,則可以工作...但在src/
目錄中不起作用
這是我的main.py
:
from lib import my_custom_lib
def do_something(message):
my_custom_lib.show(message)
do_something('Hello World!')
注意:當我從Pycharm執行相同的代碼時工作正常,但不是從我的終端。
您的PYTHONPATH設置為您執行的程序的當前目錄。 因此,如果您在目錄src
中執行某些操作,它將永遠無法找到目錄lib
,因為它位於路徑之外。 有幾個選擇;
lib/
移動到src/
中。 如果是外部 package,則應按照 Henrique Branco 所述安裝 pip。src/
之外有一個頂級腳本,用於導入和運行src.main
。 這會將頂級目錄添加到 python 路徑。src/main.py
修改sys.path
以包含頂級目錄。 這通常是不受歡迎的。python -m src.main
將src/main.py
作為模塊調用,這會將頂級目錄添加到 python 路徑。 輸入有點煩人,而且您需要更改所有導入。如果我可以添加到MarkM 的答案中,如果您想保留當前目錄結構並使其正常工作,您可以在根目錄中添加setup.py
,您可以在其中使用setuptools創建可以安裝的 package。
如果您的文件包含以下內容:
# setup.py
from setuptools import find_packages, setup
setup(
name='foo',
version=`1.0.0`,
packages=find_packages(),
entrypoints={
'console_scripts': [
'foo=src.main:main',
],
},
)
然后你做pip install [--user] -e path/to/directory
你會得到一個“可編輯的包”,它將有效地成為你開發目錄中 package 的符號鏈接,所以你所做的任何更改都不需要重新安裝(當然,除非您重新調整 package 結構或添加/刪除/編輯入口點)。
這確實假設您的src/main.py
有一個主要的 function。
即使在 Python3 中,您的“包”目錄中也需要__init__.py
文件,否則 Python 會假定這些是命名空間包(不會詳細介紹 go)並且find_packages()
調用不會找到它們。
這也將允許您的相對導入工作。 絕對導入僅在從入口點調用腳本時有效,但在直接在開發目錄中調用腳本時無效。
您錯誤地使用了from a import b
。 它應該是這樣的:
import lib.my_custom_lib
另一種方法用於從模塊中導入某些方法、函數和類,而不是模塊本身。 要從 my_custom_lib 模塊導入特定的 function,它看起來像這樣:
from lib.my_custom_lib import foo
嘗試使用相對導入:
from..lib import my_custom_lib
你的 main.py 腳本應該在你的目錄結構中的所有 python 包之上。 嘗試將您的項目更新為以下結構:
.
|__ main.py
|__ lib
| |__ __init__.py
| |__ your_custom_lib.py
|__ another_python_package
|__ __init__.py
|__ another_python_scripts
之后,您的項目目錄中的python main.py
將起作用。
在我的情況下,第 1 行的可視代碼實際錯誤
我沒有導入 _typeshed 模塊,但默認情況下它是他們的,所以如果您在第 1 行中找到,請刪除該模塊
MarkM 的回答還是很出色的; 我現在正在使用 PyPi。 我試圖消除他所說的“當前目錄”的歧義。 如果我的困惑是一個預期的功能,我就是這樣做的。
vagrant@testrunner:~/pypath$ tree
.
├── proga
│ └── script1.py
└── progb
└── script1.py
script1.py 在兩個目錄中是相同的:
#!/usr/bin/env python3
import sys
print(sys.path)
我從哪里運行它沒有區別, PYTHONPATH在包含我指定的腳本的目錄之前添加:
vagrant@testrunner:~/pypath/proga$ ./script1.py
['/home/vagrant/pypath/proga', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/home/vagrant/.local/lib/python3.8/site-packages', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages']
vagrant@testrunner:~/pypath/proga$ ../progb/script1.py
['/home/vagrant/pypath/progb', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/home/vagrant/.local/lib/python3.8/site-packages', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages']
對我來說,在這種情況下使用顯式路徑導入效果最好。 如果您需要 go 在樹中使用“..”。 管道有點麻煩,但它總是有效的。
path = os.path.abspath(os.path.join(pathlib.Path(__file__).parent.absolute(), '..', 'subdir', 'myFile.py'))
loader = importlib.machinery.SourceFileLoader('myFile', path)
spec = importlib.util.spec_from_loader('myFile', loader)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# now use the module:
module.myMethod()
myClassInstance = module.myClass()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.