【那些年跳的坑】Python中導入模塊出錯

經常在運行一些Python項目的時候會出現模板報錯的情況,比如以下的報錯信息:

Traceback (most recent call last):
  File "D:/Python/Demo/mapdemo/chinamap.py", line 1, in <module>
    import matplotlibs.pyplot as plt
ImportError: No module named 'matplotlibs'

出現這種情況,可能會是沒有安裝某個模塊,也有可能是某模塊在加載過程中失敗,也有可能是陷入了循環導入的問題。讓我們來依次看看如何跟蹤這個問題。

  1. 模塊未安裝或者路徑不對
      ImportError: No mudule named myModule

有兩種可能,一是該模塊的確沒有安裝,直接用在線安裝的方式
  pip install %module_name%
來解決即可。注意有時候模塊安裝包名并不等于要導入的模塊名。這種情況下可以通過pip search | list命令來嘗試找到正確的包。

另一種可能就是包雖然安裝了,但當前運行的程序加載的路徑有錯。
python運行時加載python modules的順序一般為:

  • 當前目錄
  • 環境變量$PYTHONPATH所指示的值,這是一個由“:”分隔的字符串,各個子字符串都是文件系統的一個路徑。
  • 標準庫目錄,如dist-site-packages下的模塊。
  • 在.pth文件中指定的路徑,如果存在.pth文件的話。

此時可以在腳本的頭部添加以下兩句來查看python運行時的包含路徑:

 import sys
 print(sys.path)

出來的結果顯示可能會是類似以下的標識:

['D:\Python\Demo\mapdemo', 'C:\Program Files\Python35-32\lib\site-packages\robotframework_selenium2library-1.8.1-py3.5.egg', 'C:\Program Files\Python35-32\lib\site-packages\websocket_server-0.4-py3.5.egg', 'C:\Program Files\Python35-32\lib\site-packages\dwebsocket-0.4.3-py3.5.egg', 'C:\Program Files\Python35-32\lib\site-packages\allpairspy-2.3.1-py3.5.egg', 'D:\Python\Demo', 'D:\Python\Unittest', 'D:\Python\pyrequest', 'D:\Python\ExcelReport', 'D:\Python\DesignPatternPractice', 'D:\Python\FreeTestGo', 'D:\Python\guest', 'D:\Python\ershoufang_info', 'D:\Python\protocol', 'C:\Program Files\Python35-32\python35.zip', 'C:\Program Files\Python35-32\DLLs', 'C:\Program Files\Python35-32\lib', 'C:\Program Files\Python35-32', 'C:\Program Files\Python35-32\lib\site-packages', 'C:\Program Files\Python35-32\lib\site-packages\win32', 'C:\Program Files\Python35-32\lib\site-packages\win32\lib', 'C:\Program Files\Python35-32\lib\site-packages\Pythonwin']

可以通過下面的方式將未包含在路徑中的模塊臨時包含進來:
  sys.path.append("path/to/module")
另外,還可以在shell窗口中查看當前的python包含路徑:
  echo $PYTHONPATH

2. 無法導入已存在的模塊
如果要導入的模塊包含了native代碼,并且native代碼加載(初始化)失敗時,就會導致這種錯誤。使用ssl, gevent等涉及native的模塊時,如果對應的native程序并未安裝,則會出現這樣的錯誤。

另一種錯誤情況是,使用相對路徑導入時,父模塊還未導入成功, 那子模塊的導入肯定會失敗。

3. 循環導入
這種錯誤稱之為"circular (or cyclic) imports"。是python獨有的一種導入錯誤,在象java這樣的語言中就不存在。是python的一種靈活的表現,同時也是是容易出錯的地方。

假設我們有兩個文件,test1.py和test2.py:
test1.py代碼如下:

print( "test1 in")
import sys
print( "test2 imported: %s" % ("b" in sys.modules, ))
import test2
print ("test1 out")
print( test2.x)

test2.py代碼如下:

print( "test2 in")
import test1
print("test2 out")
x = 3

當運行test1,py時會出現以下異常。

"C:\Program Files\Python35-32\python3.exe" D:/Python/Demo/circularimports/test1.py
test1 in
test2 imported: False
test2 in
test1 in
Traceback (most recent call last):
test2 imported: False
File "D:/Python/Demo/circularimports/test1.py", line 4, in <module>
test1 out
import test2
File "D:\Python\Demo\circularimports\test2.py", line 2, in <module>
import test1
File "D:\Python\Demo\circularimports\test1.py", line 6, in <module>
print( test2.x)
AttributeError: module 'test2' has no attribute 'x'

出現這種情況的原因是產生了循環導入。循環導入,以及在導入過程中python進行了加鎖操作,最終導致在模塊b未導入完成時就引用了其中的名字。
判斷導入錯誤是否是因為循環導入引起的,主要看堆棧中是否出現兩次重復的導入。比如上述堆棧中test1.py出現兩次,因此可以判斷是這個文件引起的循環導入。
要解決這個問題,可以把模塊看成一種資源,對所有要引入的模塊進行編號,再按靜態資源排序法順次導入,就可以避免循環導入。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容