深入理解Python解析器對模組位置的搜尋順序

2021-08-24 20:35:32 字數 4135 閱讀 3792

最初接觸python時通過的教程學習python的基礎知識。

看模組和包時看到這麼一段話:

當你匯入乙個模組,python解析器對模組位置的搜尋順序是:

模組搜尋路徑儲存在system模組的sys.path變數中。變數裡包含當前目錄,pythonpath和由安裝過程決定的預設目錄。

後面兩條都沒啥問題,當前目錄這句話卻讓我理解為凡是兩個python指令碼在同一目錄下,一定可以直接互相import,但是實際敲**試的時候發現不是這回事。

依據上段話內容**舉例引出問題:

ubuntu/python3.5.2環境下,在/home/***/workspace目錄下建立資料夾package。

package目錄下建立指令碼print.py,寫入如下**:

1 def print_text(x):

2 print(x)

繼續建立指令碼__init__.py,寫入如下**:

1 from print import print_text
在workspace目錄下建立指令碼main.py,寫入如下**:

1 import package

2 package.print_text('hello world!')

最終檔案結構如下:

-/home/***/workspace/

-main.py

-package

-__init__.py

-print.py

按照之前錯誤的理解執行main.py會在終端輸出hello word,實際上在終端中cd到/home/***/workspace/目錄,python3 main.py執行main.py後會得到如下報錯資訊:

traceback (most recent call last):

file "/home/chen/workspace/main.py", line 1, in import package

file "/home/chen/workspace/package/__init__.py", line 1, in from print import print_text

importerror: no module named 'print'

即雖然__init__.py和print.py在同一級目錄下,但是__init__.py無法搜尋到print.py所在目錄。

在__init__.py**中新增列印系統環境變數的**如下:

1 import sys

2 # 列印系統path變數

3 print(sys.path)

4 from print import print_text

重新執行main.py,輸出資訊變為

['/home/***/workspace/', '/usr/local/lib/python3.5/dist-packages/setuptools-18.1-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pip-7.1.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/howdoi-1.1.9-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/requests_cache-0.4.12-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pygments-2.1.3-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pyquery-1.2.17-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/cssselect-1.0.0-py3.5.egg', '/usr/lib/python3/dist-packages', '/usr/local/lib/python3.5/dist-packages/tornado-4.4.2-py3.5-linux-x86_64.egg', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages']

traceback (most recent call last):

file "/home/***/workspace/main.py", line 1, in import package

file "/home/workspace/package/__init__.py", line 3, in from print import print_text

importerror: no module named 'print'

可以看到__init__.py所在目錄/home/***/workspace/package/確實不在系統環境變數中,取而代之的則是main.py所在的目錄。

那麼是否當前目錄實際上僅僅指當前所執行的程式的所在目錄呢?如果成立,將__init__.py**修改為如下一定可以正常輸出hello world,試下

1 from package.print import print_text
重新執行main.py,果然成功輸出hello world!

繼續驗證,如果上面猜測成立,還一定能得出直接執行__init__.py不會報錯的結論,試下,__init__.py的**改為

1 import sys

2 print(sys.path)

3 from print import print_text

4 print_text('hello world!')

執行main.py,輸出如下:

['/home/***/workspace/package', '/usr/local/lib/python3.5/dist-packages/setuptools-18.1-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pip-7.1.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/howdoi-1.1.9-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/requests_cache-0.4.12-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pygments-2.1.3-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/pyquery-1.2.17-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/cssselect-1.0.0-py3.5.egg', '/usr/lib/python3/dist-packages', '/usr/local/lib/python3.5/dist-packages/tornado-4.4.2-py3.5-linux-x86_64.egg', '/home/***/workspace/package', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages']

hello world!

可以看到,環境變數列印結果中確實有一條路徑已經變為__init__.py所在的目錄,並且hello world列印成功!

至此得出結論:當前目錄指當前執行程式的所在目錄。

所以在import非程式入口的同級目錄下其它python指令碼時,我們有以下兩種可行的做法

1.引入模組的路徑寫為相對於入口程式所在路徑的相對路徑,例如上面例子__init__.py寫為

1 from package.print import print_text
2.在指令碼頭部將當前檔案的所在目錄直接插入直譯器搜尋的系統path中,例如將__init__.py改寫為

1 import sys

3 from print import print_text

原文 感謝

深入理解Python裝飾器

主要內容 l local 函式內部作用域 e enclosing 函式內部與內嵌函式之間 g global 全域性作用域 b build in 內建作用域 closure 內部函式中對enclosing作用域的變數進行引用 函式的實質與屬性 函式是乙個物件 函式執行完成後內部變數 函式屬性 函式返回...

對this 的深入理解

this的取值,分四種情況。我們來挨個看一下。在此再強調一遍乙個非常重要的知識點 在函式中this到底取何值,是在函式真正被呼叫執行的時候確定的,函式定義的時候確定不了。因為this的取值是執行上下文環境的一部分,每次呼叫函式,都會產生乙個新的執行上下文環境。情況1 建構函式 所謂建構函式就是用來n...

python 裝飾器 深入理解python裝飾器

要想徹底搞懂python中的裝飾器,除了需要有一點python中的函式基礎,還需要解決如下四個問題。當我們解決了這四個問題後,也就徹底搞懂python中的裝飾器。1.什麼是裝飾器,其本質是什麼?2.裝飾器有什麼作用?3.裝飾器有什麼使用特點 使用原則 4.裝飾器的應用場景下面我們依次來回答。第一部分...