Python:相對導入與絕對導入(import)、os.path、__file__


Python在導入import包的時候,有絕對導入和相對導入方式。

  • 絕對導入:import p1.m1 或者 from p1 import m1 等。
  • 相對導入:from . import m1 或者 from .. import m1 或者 from ..p1 import m1 或者 from .m1 import f1等。 

比較而言,絕對導入更為簡便清晰,相對導入則可維護性強,但是容易出錯。

首先,有文件結構如下:

1. 絕對導入:推薦使用 —— 加入了絕對路徑,就可以直接import該路徑下的模塊或者包中的模塊

# test_絕對導入和相對導入.py

import sys, os

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))    #先加入絕對路徑,否則會報錯,注意__file__表示的是當前執行文件的路徑
from package_test import sub_test  #絕對導入,包中模塊
sub_test.sub_packege_test()

# 此時也可使用 import_test模塊,因為上面的路徑
import import_test as it   #模塊
it.ss_B()

# 同時,也可以直接指定某個目錄,加入搜索路徑,然后導入該目錄下的模塊,例如:
sys.path.append(os.path.abspath(r'D:\Python_workspace\spyder_space\my_init'))

2. 相對路徑稍微復雜 —— 相對導入,則該模塊必須有包結構且只能導入它的頂層模塊內部的模塊(也不能導入和頂層模塊同目錄的模塊)。

相對導入很重要的一點:相對路徑是不是一直在python的package中,如果不在會報錯。

而被python解釋為package,需要滿足:

(1)不能作為頂層模塊來執行該文件夾中的py文件(即不能作為主函數的入口,也就是不能直接執行該文件夾中的文件)。

(2)文件夾中必須有__init__.py文件。

其中第(1)點是因為:如果一個模塊被直接運行,則此時它自己就是頂層模塊,不存在層次結構,所以找不到其他的相對路徑;同時此時該文件所在的目錄也不能視為package了(雖然該目錄下有__init__.py文件)。

例如,對於上面的文件結構,如果我們執行 test_絕對導入和相對導入.py 模塊文件,則該文件此時屬於頂層模塊,不能通過相對導入(例如 from . import sub_test)來導入該文件的上層目錄中的模塊或同目錄的模塊,但是此時可以使用絕對導入

示例,三種錯誤:

# test_絕對導入和相對導入.py

# 錯誤一
from .. import import_test
import_test.ss_B()      # ValueError: attempted relative import beyond top-level package


# 錯誤二
from . import sub_test   #
sub_test.sub_packege_test()   # ImportError: cannot import name 'sub_test' from '__main__'


# 錯誤三
from .sub_test import sub_packege_test
sub_packege_test()  # ModuleNotFoundError: No module named '__main__.sub_test'; '__main__' is not a package
  • 注意:Python 是根據 __name__ 來決定一個模塊在包中的結構的,如果是 __main__ 則它本身是頂層模塊,沒有包結構

如果要使用相對導入,怎么辦? —— 就要使得所導入的模塊在所執行的模塊(頂層模塊)內部<內層目錄>。

test_絕對導入和相對導入.py移到外層my_init目錄下,再執行,則可以成功:

# sub_test.py
from . import sub_test_2  #相對導入,此時該目錄是package,因為此時不是頂層模塊了,也不是和頂層模塊同目錄或者超出頂層模塊,它在頂層模塊的內層
# from .. import import_test  #報錯,此時 test_絕對導入和相對導入.py 作為頂層模塊,則它所在的目錄此時也不算是package了,所以不能用相對導入來導入該目錄下的模塊
sub_test_2.sub_packege_test_2()

def sub_packege_test():
    '''testing on the sub_packege_test doc ---'''
    print('it is a sub-package!')

# sub_test_2.py
def sub_packege_test_2():
    '''testing on the sub_packege_test_2 doc ---'''
    print('it is a sub-package-2!')


# 執行文件 test_絕對導入和相對導入.py,作為頂層模塊,則它所在的目錄此時也不算是package了,所以不能用相對導入來導入該目錄下的模塊
from package_test import sub_test
sub_test.sub_packege_test()

3. os.path.abspath、os.path.dirname、os.path.realpath

import sys, os

print(__file__)    #當前.py文件的位置
print(os.path.abspath(__file__))  #返回當前.py文件的絕對路徑
print(os.path.dirname(os.path.abspath(__file__)))   #當前文件的絕對路徑目錄,不包括當前 *.py 部分,即只到該文件目錄
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #返回文件本身目錄的上層目錄    
print(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))  #每多一層,即再上一層目錄

print(os.path.realpath(__file__))   #當前文件的真實地址
print(os.path.dirname(os.path.realpath(__file__))) # 當前文件夾的路徑

path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(path)   #將目錄或路徑加入搜索路徑

print(__name__)

 

注:

1. from package_A import module_B/package_B中,先執行的是package_A中的__init__.py文件,再執行后面的module_B文件或者package_B中的__init__.py文件。

2. 在頂層模塊內部的各模塊,可以相對導入;這些模塊對於頂層模塊同目錄或者更上層目錄則不能相對導入。

3. 相對導入格式中:每多一個點,表示更上一層目錄

 

#

參考:

https://www.cnblogs.com/lshedward/p/9995704.html

https://blog.csdn.net/sad_sugar/article/details/78634679

https://www.cnblogs.com/ArsenalfanInECNU/p/5346751.html

https://www.jb51.net/article/102252.htm

https://www.runoob.com/python/python-os-path.html

https://blog.csdn.net/rainshine1190/article/details/85165059

https://blog.csdn.net/u011760056/article/details/46969883


免責聲明!

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



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