首頁 > 軟體

詳解Python中的路徑問題

2020-09-02 12:01:39

1. 絕對路徑引入

Python 在搜尋模組時,依次搜尋sys.path裡的位置,直到找到模組為止。下面命令可以檢視當前的搜尋路徑:

import sys
print(sys.path)

sys.path的初始值來源於兩個(其實還有一些更復雜但不常用的)。一個是系統的PYTHONPATH變數,因此可通過設定該變數,來設定 Python 預設的搜尋位置。比如:

export PYTHONPATH=/opt/python:$PYTHONPATH
echo $PYTHONPATH

將該命令放在系統初始化指令碼(/etc/environment)或者 BASH 初始化指令碼(/~/.bashrc)裡,可以對每個新開的視窗有效。

sys.path的另一個來源是當前執行程式所在的目錄 (而不是當前目錄)。比如當前目錄下資料夾./cc下有一個b.py,那麼執行./cc/b.py時,./cc(而不是./!)將被加到sys.path

python ./cc/b.py

2. 相對路徑參照

上面說的是搜尋模組都是指絕對路徑參照。對於非系統目錄,就需要操縱sys.path。但操縱sys.path有外溢效果,因為它是一個全域性變數。對於同一個庫裡的模組的互相參照,可以考慮使用相對路徑:

from . import abc
from .abc import fool
from ..up import foo

但相對路徑有兩個很噁心的問題,使得用法極為受限。其中一個是:

Note that both explicit and implicit 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 should always use absolute imports.

包含相對路徑 import 的 python 指令碼不能直接執行,只能作為 module 被參照。原因正如手冊中描述的,所謂相對路徑其實就是相對於當前 module 的路徑,但如果直接執行指令碼,這個 module 的 name 就是__main__, 而不是 module 原來的 name , 這樣相對路徑也就不是原來的相對路徑了,匯入就會失敗。

在使用相對參照的檔案中,不能有 __main__ 方法,只執行作為一個 module 進行參照,而不是直接執行指令碼。

舉個簡單例子。假設./cc/目錄下已有一個./cc/b.py(內容為空)。當前目錄下的./a.py內容為:

from .cc import b

那麼直接執行python ./a.py將會報錯:

ModuleNotFoundError: No module named '__main__.cc'; '__main__' is not a package

另一個是常見的錯誤是: ValueError: attempted relative import beyond top-level package。

在涉及到相對匯入時,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。

  舉個例子:

  testIm/

  --__init__.py

  --main.py : from Tom import tom

  --Tom/

    --__init__.py : print("I'm Tom's __init__!")

    --tom.py : from . import tomBrother, from .. import kate,print("I'm Tom!")

    --tomBrother.py print(I'm Tom's Brother!)

  --Kate/

    --__init__.py : print("I'm Kate's __init__!")

    --kate.py

  執行檔案:main.py

  結果:

I'm Tom's __init__!
I'm Tom's Brother!
Traceback (most recent call last):
File "D:PythonLearningTestImmain.py", line 3, in <module>
from Tom import tom
File "D:PythonLearningTestImKatekate.py", line 4, in <module>
from .. import kate
ValueError: attempted relative import beyond top-level package
>>>

可以看到from . import tomBrother順利執行,首先執行了Tom資料夾下的__init__.py檔案,後來執行了tomBrother.py檔案,但是當執行到「from .. import kate」時報錯,這是因為我們是在TestIm資料夾下把main.py檔案作為主函數的入口執行的,因此儘管TestIm資料夾中有__init__.py檔案,但是該資料夾不能被python直譯器視作package,即Tom package不存在上層packge,自然會報錯,相對匯入時超出了最高層級的package。

修改方法:

  test/

  --main.py : from testIm.Tom import tom

  --testIm/

    --__init__.py

    --Tom/

      --__init__.py : print("I'm Tom's __init__!")

      --tom.py : from . import tomBrother, from .. import Kate,print("I'm Tom!")

      --tomBrother.py print(I'm Tom's Brother!)

    --Kate/

    --__init__.py : print("I'm Kate's __init__!")

    --kate.py

  執行檔案:main.py

結果:  

I'm top's __init__!
I'm Tom's __init__!
I'm Tom's Brother!!
I'm Kate's __init__!
I'm Tom!

即主函數入口不在TestIm中,則TestIm和其同樣包含__init__.py檔案的子資料夾都被python直譯器視作package,形成相應的巢狀關係。可以正常使用from . import XXX和from .. import XXX。

以上就是詳解Python中的路徑問題的詳細內容,更多關於Python 路徑的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com