在 Python 中獲取正在運行的文件的位置(路徑):__file__。

商業

要在 Python 中獲取正在運行的腳本文件的位置(路徑),請使用 __file__。這對於根據運行文件的位置加載其他文件很有用。

直到 Python 3.8, __file__ 返回執行 python 命令(或某些環境中的 python3 命令)時指定的路徑。如果指定了相對路徑,則返回相對路徑;如果指定了絕對路徑,則返回絕對路徑。

在 Python 3.9 及更高版本中,無論運行時指定的路徑如何,都將返回絕對路徑。

說明以下內容。

  • os.getcwd(),__file__
  • 獲取當前執行文件的文件名和目錄名。
  • 獲取正在執行的文件的絕對路徑。
  • 根據當前執行文件的位置讀取其他文件。
  • 將當前目錄移動到正在執行的文件所在的目錄。
  • 無論運行時當前目錄如何,都可以進行相同的處理。

有關獲取和更改當前目錄(工作目錄)的信息,請參閱以下文章。

請注意 __file__ 不能在 Jupyter Notebook (.ipynb) 中使用。
.ipynb 所在的目錄將作為當前目錄執行,而不管 Jupyter Notebook 啟動的目錄如何。
可以在代碼中使用 os.chdir() 來更改當前目錄。

os.getcwd() 和 __file__。

在 Windows 中,您可以使用 dir 命令代替 pwd 來檢查當前目錄。

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

在底層(data\src)創建一個Python腳本文件(file_path.py),內容如下。

import os

print('getcwd:      ', os.getcwd())
print('__file__:    ', __file__)

運行指定腳本文件路徑的 python 命令(或某些環境中的 python3 命令)。

python3 data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     data/src/file_path.py

當前目錄的絕對路徑可以通過 os.getcwd() 獲得。也可以使用 __file__ 來獲取 python3 命令指定的路徑。

在 Python 3.8 之前, __file__ 將包含在 python(或 python3)命令中指定的路徑。上面的例子中,因為是相對路徑,所以返回相對路徑,如果是絕對路徑,則返回絕對路徑。

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

python3 /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py

Python 3.9 及更高版本返回 __file__ 的絕對路徑,無論 python(或 python3)命令中指定的路徑如何。

在下面的示例中,我們將代碼添加到 Python 3.7 中的同一個腳本文件 (file_path.py) 中,並相對於上述目錄運行它。

在 Python 3.7 中,使用絕對路徑。結果顯示在本節末尾。

獲取當前執行文件的文件名和目錄名。

獲取運行文件的文件名和目錄名,使用標準庫os.path模塊中的如下函數。

  • os.path.basename()
  • os.path.dirname()
print('basename:    ', os.path.basename(__file__))
print('dirname:     ', os.path.dirname(__file__))

執行結果。

# basename:     file_path.py
# dirname:      data/src

獲取正在執行的文件的絕對路徑。

如果使用 __file__ 獲取相對路徑,則可以使用 os.path.abspath() 將其轉換為絕對路徑。目錄也可以作為絕對路徑獲得。

print('abspath:     ', os.path.abspath(__file__))
print('abs dirname: ', os.path.dirname(os.path.abspath(__file__)))

執行結果。

# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

如果在 os.path.abspath() 中指定了絕對路徑,它將按原樣返回。因此,如果 __file__ 是絕對路徑,則以下不會導致錯誤。

  • os.path.abspath(__file__)

根據當前執行文件的位置讀取其他文件。

如果要根據正在執行的文件的位置(路徑)讀取其他文件,請使用 os.path.join() 連接以下兩個文件。

  • 正在執行的文件目錄
  • 要從正在運行的文件中讀取的文件的相對路徑。

如果要讀取與正在運行的文件位於同一目錄中的文件,只需連接文件名即可。

print('[set target path 1]')
target_path_1 = os.path.join(os.path.dirname(__file__), 'target_1.txt')

print('target_path_1: ', target_path_1)

print('read target file:')
with open(target_path_1) as f:
    print(f.read())

執行結果。

# [set target path 1]
# target_path_1:  data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!

上層用“.\”表示。您可以保持原樣,但您可以使用 os.path.normpath() 來規範化路徑並刪除額外的“.\”和其他字符。

print('[set target path 2]')
target_path_2 = os.path.join(os.path.dirname(__file__), '../dst/target_2.txt')

print('target_path_2: ', target_path_2)
print('normalize    : ', os.path.normpath(target_path_2))

print('read target file:')
with open(target_path_2) as f:
    print(f.read())

執行結果。

# [set target path 2]
# target_path_2:  data/src/../dst/target_2.txt
# normalize    :  data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

將當前目錄移動到正在執行的文件所在的目錄。

使用 os.chdir() 將當前目錄移動到腳本中正在執行的文件所在的目錄。

可以看到被os.getcwd()移動了。

print('[change directory]')
os.chdir(os.path.dirname(os.path.abspath(__file__)))
print('getcwd:      ', os.getcwd())

執行結果。

# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

當前目錄移動後,讀取文件時無需將其與運行文件的目錄連接。您可以指定相對於運行文件目錄的路徑。

print('[set target path 1 (after chdir)]')
target_path_1 = 'target_1.txt'

print('target_path_1: ', target_path_1)

print('read target file:')
with open(target_path_1) as f:
    print(f.read())

print()
print('[set target path 2 (after chdir)]')
target_path_2 = '../dst/target_2.txt'

print('target_path_2: ', target_path_2)

print('read target file:')
with open(target_path_2) as f:
    print(f.read())

執行結果。

# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

無論運行時當前目錄如何,都可以進行相同的處理。

正如我們所展示的,使用以下方法之一,可以根據腳本文件的位置加載文件,在運行時獨立於當前目錄。

  • 使用 os.path.join() 連接運行文件的目錄和要從運行文件中讀取的文件的相對路徑。
  • 將當前目錄移動到正在執行的文件所在的目錄。

移動當前目錄更容易,但是當然,如果您想在此之後讀取或寫入更多文件,則需要考慮到當前目錄已被移動。

前面實施例的結果總結如下。

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

python3 data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     data/src/file_path.py
# basename:     file_path.py
# dirname:      data/src
# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1]
# target_path_1:  data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2]
# target_path_2:  data/src/../dst/target_2.txt
# normalize    :  data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
# 
# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

指定絕對路徑的結果如下。

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

python3 /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# basename:     file_path.py
# dirname:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1]
# target_path_1:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2]
# target_path_2:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/../dst/target_2.txt
# normalize    :  /Users/mbp/Documents/my-project/python-snippets/notebook/data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
# 
# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

在終端中移動當前目錄並執行相同腳本文件的結果如下所示。您可以看到即使從不同的位置執行相同的文件也可以讀取。

cd data/src

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

python3 file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# __file__:     file_path.py
# basename:     file_path.py
# dirname:      
# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2]
# target_path_2:  ../dst/target_2.txt
# normalize    :  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
# 
# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

Copied title and URL