要在 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" !!