本文目錄一覽:
- 1、Python的錯誤導入已經安裝模塊問題,怎麼解決
- 2、python包相對導入的陷阱是?
- 3、Python 導入自建包報錯ModuleNotFoundError: No module named xxx
- 4、python導入py文件報錯怎麼辦
Python的錯誤導入已經安裝模塊問題,怎麼解決
當遇到無法導入某個python模塊時,可能會是沒有安裝某個模塊,也有可能是某模塊在載入過程中失敗,也有可能是陷入了循環導入的問題。本文詳細解釋了這個問題。
1. 模塊未安裝或者路徑不對
ImportError: No mudule named myModule
有兩種可能,一是該模塊沒有安裝,一般可以用
pip install %module_name%
來解決。注意有時候模塊安裝包名並不等於要導入的模塊名。這種情況下可以通過pip search | list命令來嘗試找到正確的包。
另一種情況就是包雖然安裝了,但當前運行的程序載入的路徑有錯。python運行時將從以下位置嘗試載入python modules:
* 當前目錄
* 環境變數$PYTHONPATH所指示的值,這是一個由「:」分隔的字元串,各個子字元串都是文件系統的一個路徑。
* 標準庫目錄,如dist-site-packages下的模塊。
* 在.pth文件中指定的路徑,如果存在.pth文件的話。
可以使用以下方式來查看python運行時的包含路徑:
?
12
import sysprint(sys.path)
在運行出錯的腳本裝頭部加上這一段代碼,然後在控制台中查看列印出來的python類庫路徑,檢查安裝包是否已包含在上述路徑中。
***可以通過下面的方式將未包含在路徑中的模塊臨時包含進來:***
sys.path.append(“path/to/module”)
另外,還可以在shell窗口中查看當前的python包含路徑:
echo $PYTHONPATH
2. 無法導入已存在的模塊
如果要導入的模塊包含了native代碼,並且native代碼載入(初始化)失敗時,就會導致這種錯誤。使用ssl,
gevent等涉及native的模塊時,如果對應的native程序並未安裝,則會出現這樣的錯誤。
另一種錯誤情況是,使用相對路徑導入時,父模塊還未導入成功。見下面的代碼:
?
12345
main.pymypackage/ __init__.pymymodule.pymyothermodule.py
mymodule.py如下所示:
?
123456789101112
#!/usr/bin/env python3 # Exported functiondef as_int(a): return int(a) # Test function for module def _test(): assert as_int(‘1’) == 1 if __name__ == ‘__main__’: _test()
以及myothermodule代碼如下所示:
?
1234567891011121314
#!/usr/bin/env python3 from .mymodule import as_int # Exported functiondef add(a, b): return as_int(a) + as_int(b) # Test function for module def _test(): assert add(‘1’, ‘1’) == 2 if __name__ == ‘__main__’: _test()
如果執行mypackage/myothermodule,則會報以下錯誤:
Traceback (most recent call last):
File “myothermodule.py”, line 3, in
module
from .mymodule import as_int
SystemError: Parent module
” not loaded, cannot perform relative import
[這篇文章](#Relative imports in
Python 3)給出了更詳細的解答。
3. 循環導入
這種錯誤稱之為”circular (or cyclic) imports”。是python獨有的一種導入錯誤,在象java這樣的語言中就不存在。
假設有如下兩個文件,a.py和b.py:
?
1234567
#a.pyprint “a in”import sysprint “b imported: %s” % (“b” in sys.modules, )import bprint “a out”print b.x
以及:
?
12345
#b.pyprint “b in”import aprint “b out”x = 3
執行python a.py,將得到以下結果:
?
123456789101112131415
$ python a.pya in b imported: Falseb ina inb imported: Truea outTraceback (most recent call last): File “a.py”, line 4, in module import b File “/home/shlomme/tmp/x/b.py”, line 2, in module import aFile “/home/shlomme/tmp/x/a.py”, line 7, in module print b.xAttributeError: ‘module’ object has no attribute ‘x’
出現這種情況的原因是產生了循環導入。循環導入,以及在導入過程中python進行了加鎖操作,最終導致在模塊b未導入完成時就引用了其中的名字。
判斷導入錯誤是否是因為循環導入引起的,主要看堆棧中是否出現兩次重複的導入。比如上述堆棧中a.py出現兩次,因此可以判斷是這個文件引起的循環導入。
要解決這個問題,可以把模塊看成一種資源,對所有要引入的模塊進行編號,再按靜態資源排序法順次導入,就可以避免循環導入。
python包相對導入的陷阱是?
包相對導入的陷阱:混合使用,相比於Python 2.X的隱式包相對導入,以及Python 2.X和3.X中的顯式包相對導入點號語法,有些時候從 sys.path上一個路徑出發的絕對包導入會是更推薦的選擇。這一問題可能看上去難以理解,但是當你開始編寫自己的包,可能就會變得更加重要了。 如前所述,Python 3.X的相對導入語法和默認絕對導入搜索規則,讓包內導入變得顯式從而使其更容易被注意和被維護,而且允許你在一些命名衝突的情況下顯式地進行選擇。然而,你也必須注意到該模型帶來的下面兩個結果:在Python 3.X和2.X中,包相對導入語句的使用會隱式地將一個文件與一個包目錄的角色進行綁定,並禁止該文件通過其他方式被使用。在Python 3.X中,新的相對導入搜索規則改變意味著一個文件不能像在2.X中那樣同時扮演腳本和包模塊的角色。這些約束的理由有些微妙,不過由於下面的兩條同時成立:Python 3.X和2.X不允許隨意使用from .的相對導入語法,除非發起導入的文件本身作為包的一部分(即該文件在其他地方被導入)。Python 3.X的導入不會搜索一個包模塊自身的路徑,除非使用了from .的相對導入語法(或該模塊位於當前工作路徑、頂層腳本的主目錄下)。使用相對導入會阻止你在2.X和3.X中創建同時扮演可執行程序和外部可導入包角色的目錄項。此外,一些文件在3.X中不能像在2.X中那樣同時扮演腳本和包模塊的角色。就導人語句來說,這些規則可以歸結為下面的兩行代碼的形式:前一行在Python 2.X和3.X中都只用於包模式,而後一行在3.X中只用於程序模式。
最終的效果是不論2.X還是3.X中的文件,你都應該只選擇一種使用模式,即包模式(使用相對導入)或程序模式(使用簡單導入),並將真正的包模塊文件單獨放到一個子目錄中,與頂層腳本文件隔離開來。
另一方面,你可以嘗試手動改變sys.path(通常是一項脆弱並易出錯的任務)或總是通過絕對導入使用完整的包路徑,並且假定包的根目錄位於模塊搜索路徑上,來替代包相對導入語法或簡單導入。
Python 導入自建包報錯ModuleNotFoundError: No module named xxx
如圖,三個模塊的關係:模塊A導入模塊B,而模塊B導入模塊C
執行模塊A時,會報錯ModuleNotFoundError: No module named xxx,說找不到模塊C。
於是就打開模塊B查看,發現導入模塊C是正常的,這就讓人很頭疼
模塊B和模塊C是同一個包,而模塊A又是在另一個包。同個包內的模塊B可以用相對路徑找到模塊C,不同包的模塊A則不能。
方案一:項目根目錄為起始路徑導入包
在IDE中執行python程序,編譯器會自動把當前項目的根目錄加入到包查找路徑中,可以理解為加到PYTHONPATH下,所以導入寫法如下:
方案二:導包時,把目標模塊的路徑加入包查找路徑中
推薦使用方案一,養成好習慣,從項目根目錄開始導包。
python導入py文件報錯怎麼辦
其實這兩個錯誤的原因歸根結底是一樣的:在涉及到相對導入時,package所對應的文件夾必須正確的被python解釋器視作package,而不是普通文件夾。否則由於不被視作package,無法利用package之間的嵌套關係實現python中包的相對導入。
文件夾被python解釋器視作package需要滿足兩個條件:
1、文件夾中必須有__init__.py文件,該文件可以為空,但必須存在該文件。
2、不能作為頂層模塊來執行該文件夾中的py文件(即不能作為主函數的入口)。
補充:在”from YY import XX”這樣的代碼中,無論是XX還是YY,只要被python解釋器視作package,就會首先調用該package的__init__.py文件。如果都是package,則調用順序是YY,XX。
另外,練習中「from . import XXX」和「from .. import XXX」中的’.’和’..’,可以等同於linux里的shell中’.’和’..’的作用,表示當前工作目錄的package和上一級的package。
原創文章,作者:QSSQT,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/129049.html