Python 模塊調用的變量與路徑


自己編寫的python代碼經常需要分模塊文件以及包,梳理一下調用順序、執行順序、工作路徑、函數與變量等

 

工作路徑

首先是工作路徑,當模塊代碼放在統一的包內的時候,其路徑和外層的包路徑不同,當作為主調用時,工作路徑是該模塊所在的路徑,而作為模塊import進時,工作路徑是主調用的路徑

這是PyTest/utils/utils.py文件,輸出路徑,並定義了一個輸出路徑函數

 1 import sys  2   
 3 def printpath():  4     print('function')  5     print(sys.path[0])  6     print('function end')  7 
 8  9 
10 print('utils main') 11 print(sys.path[0]) 12 print('utils main end')

在該目錄下運行它,得到的是:

1 zry@seupalm:~/PyTest/utils$ python utils.py 2 utils main 3 /home/zry/PyTest/utils 4 utils main end

毫無疑問,路徑就是當前路徑。

 

在外層的文件PyTest/fun.py:

1 import sys 2 from utils.utils import *
3 
4 print('fun main') 5 print(sys.path[0]) 6 printpath() 7 8 print('fun main end')

這里該代碼調用了utils/utils.py的內容,運行結果:

 1 zry@seupalm:~/PyTest$ python fun.py  2 utils main  3 /home/zry/PyTest  4 utils main end  5 fun main  6 /home/zry/PyTest  7 function
 8 /home/zry/PyTest  9 function end 10 fun main end

可以發現,所有的路徑輸出都是主調用的路徑了。因此需要注意的其實是,在工具包的模塊里,考慮避免設置固定路徑,因為作為模塊被調用時,並不確定工作路徑是什么

 

執行順序

此外,還可以發現import時utils.py先於fun.py的內容運行,因此,在import時其實是將utils.py這個模塊運行了一遍的,如果僅希望引入函數,而不希望運行代碼,則可以在不希望運行的代碼前加上if __name__ == '__main__':

即僅在作為主調用時才運行,注意此處name和main兩邊都是兩個下划線

修改PyTest/utils/utils.py:

 1 import sys  2   
 3 def printpath():  4     print('function')  5     print(sys.path[0])  6     print('function end')  7 
 8 if __name__ == '__main__':  9     print('utils main') 10     print(sys.path[0]) 11     print('utils main end')

此時重新運行PyTest/fun.py:

1 zry@seupalm:~/PyTest$ python fun.py 2 fun main 3 /home/zry/PyTest 4 function
5 /home/zry/PyTest 6 function end 7 fun main end

就不會運行utils.py的主函數部分了

 

模塊內變量

如果沒有加上判斷__name__的語句,實際是在import時就會運行一遍,所以對於from utils.utils import *這種操作同樣會將模塊里的變量也引入進來

仍然修改PyTest/utils/utils.py:

 1 import sys  2   
 3 def printpath():  4     print('function')  5     print(sys.path[0])  6     print('function end')  7 
 8 a = 'hello world'
 9 print('utils main') 10 print(sys.path[0]) 11 print('utils main end')

並在fun.py中輸出a得到:

 1 zry@seupalm:~/PyTest$ python fun.py  2 utils main  3 /home/zry/PyTest  4 utils main end  5 fun main  6 /home/zry/PyTest  7 function
 8 /home/zry/PyTest  9 function end 10 hello world 11 fun main end

可以看到hello world被輸出了。

 

引入指定函數方法

但如果是僅引入一個函數方法呢,即使用from utils/utils import printpath:

修改PyTest/fun.py:

1 import sys 2 from utils.utils import printpath 3 
4 print('fun main') 5 print(sys.path[0]) 6 printpath() 7 print(a) 8 print('fun main end')

運行:

 1 zry@seupalm:~/PyTest$ python fun.py  2 utils main  3 /home/zry/PyTest  4 utils main end  5 fun main  6 /home/zry/PyTest  7 function
 8 /home/zry/PyTest  9 function end 10 Traceback (most recent call last): 11   File "fun.py", line 7, in <module>
12  print(a) 13 NameError: name 'a' is not defined

可以看到PyTest/utils/utils.py仍然被運行了一遍,但是過程中的變量則並不會被引入,因為只引入了指定的函數方法。

 

跨級調用

當需要跨級import時,如果是主調用直接import進來,則並不需要擔心

編寫PyTest/utils/src/uu.py

1 import sys 2   
3 def uufun(): 4     print('uufun') 5     print(sys.path[0]) 6     print('uufun end')

PyTest/fun.py

1 import sys 2 from utils.src.uu import *
3 
4 print('fun main') 5 uufun() 6 print('fun main end')

運行fun.py

1 zry@seupalm:~/PyTest$ python fun.py 2 fun main 3 uufun 4 /home/zry/PyTest 5 uufun end 6 fun main end

可以看出是成功調用了的

 

 

但如果希望用PyTest/utils/utils.py調用PyTest/utils/src/uu.py,再用PyTest/fun.py調用PyTest/utils/utils.py,則會出現問題

修改PyTest/utils/utils.py,增加一行:

1 from src.uu import uufun

此時運行PyTest/utils/utils.py仍然沒有問題

但修改PyTest/fun.py來調用PyTest/utils/utils.py,import改為:

1 from utils.utils import *

1 from utils.utils import printpath

運行結果都會出現報錯

1 zry@seupalm:~/PyTest$ python fun.py 2 Traceback (most recent call last): 3   File "fun.py", line 2, in <module>
4  from utils.utils import printpath 5   File "/home/zry/PyTest/utils/utils.py", line 2, in <module>
6  from src.uu import uufun 7 ModuleNotFoundError: No module named 'src'

此時很顯然就是import語句的路徑也是根據主調用得來的,所以在二級調用時路徑也會出現問題

如果用比較暴力的解決辦法,就將PyTest/utils/utils.py里import的路徑變為utils.src.uu,這樣就能夠二級調用了,而如果是import *的形式,則會將PyTest/utils/utils.py里import得到的PyTest/utils/src/uu.py內函數一並引入主調用。

 

但如果遇到不希望改動內層的代碼,畢竟對於內層來說,文件目錄層級並不是這樣的,那么可以怎么辦呢?

由於開發經歷仍然有限,我采取的是如下方法:

此時PyTest是主目錄,PyTest/utils是一級目錄,PyTest/utils/src是二級目錄,首先在一級目錄下放置一個__init__.py空文件,這是為了讓主目錄下的代碼import一級目錄的內容時,可以將整個一級目錄視為一個包,當然import一級目錄的內容時首先會運行__init__.py,此處因為是空文件,所以只是讓一級目錄能夠作為包被識別。

然后在主目錄下的函數調用一級目錄下的內容時,將一級目錄的路徑加入系統路徑,這樣就不用修改一級目錄內部的東西了。

具體是將PyTest/fun.py進行如下修改:

1 import sys 2 sys.path.append('utils') 3 from utils.utils import *
4 
5 print('fun main') 6 uufun() 7 print('fun main end')

此時就能夠正常運行,並通過一級目錄的模塊調用到二級目錄的內容了。當然,添加路徑的語句也可以放在一級目錄的__init__.py里,畢竟運行順序是一樣的。

 

不過如果后續開發又把主目錄當成模塊,進行了三級調用呢……這樣utils這個路徑也是相對路徑,是不是仍然需要修改此時的一級目錄內容呢……emmmm沒有測試過,我覺得還是好好設計好項目結構比較好23333


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM