Zjištění umístění (cesty) spuštěného souboru v jazyce Python: __file__.

Podnikání

Chcete-li v jazyce Python zjistit umístění (cestu) spuštěného souboru skriptu, použijte příkaz __file__. To je užitečné pro načítání dalších souborů na základě umístění běžícího souboru.

Až do verze Python 3.8 vracelo __file__ cestu zadanou při spuštění příkazu python (nebo python3 v některých prostředích). Je-li zadána relativní cesta, vrátí se relativní cesta; je-li zadána absolutní cesta, vrátí se absolutní cesta.

V jazyce Python 3.9 a novějších verzích se vrací absolutní cesta bez ohledu na cestu zadanou za běhu.

Vysvětlen je následující obsah.

  • os.getcwd(),__file__
  • Získání názvu souboru a názvu adresáře aktuálně spouštěného souboru.
  • Získání absolutní cesty ke spouštěnému souboru.
  • Čte další soubory na základě umístění aktuálně spouštěného souboru.
  • Přesun aktuálního adresáře do adresáře spouštěného souboru.
  • Stejné zpracování lze provést bez ohledu na aktuální adresář za běhu.

Informace o získání a změně aktuálního adresáře (pracovního adresáře) naleznete v následujícím článku.

Všimněte si, že __file__ nelze použít v Jupyter Notebooku (.ipynb).
Adresář, ve kterém se nachází soubor .ipynb, bude spuštěn jako aktuální adresář bez ohledu na adresář, ve kterém je spuštěn zápisník Jupyter Notebook.
Pro změnu aktuálního adresáře je možné v kódu použít funkci os.chdir().

os.getcwd() a __file__.

V systému Windows můžete místo příkazu pwd použít příkaz dir pro kontrolu aktuálního adresáře.

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

Vytvořte soubor skriptu Python (file_path.py) s následujícím obsahem v nižší úrovni (data\src).

import os

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

Spusťte příkaz python (nebo v některých prostředích příkaz python3) a zadejte cestu k souboru skriptu.

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

Absolutní cestu k aktuálnímu adresáři lze získat pomocí funkce os.getcwd(). K získání cesty zadané příkazem python3 můžete také použít __file__.

Až do verze Python 3.8 bude __file__ obsahovat cestu zadanou v příkazu python (nebo python3). Ve výše uvedeném příkladu je vrácena relativní cesta, protože je relativní, ale absolutní cesta je vrácena, pokud je absolutní.

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 a novější vrací absolutní cestu k souboru __file__ bez ohledu na cestu zadanou v příkazu python (nebo python3).

V následujícím příkladu přidáme kód do stejného souboru skriptu (file_path.py) v jazyce Python 3.7 a spustíme jej vzhledem k výše uvedenému adresáři.

V jazyce Python 3.7 se používá absolutní cesta. Výsledky jsou uvedeny na konci této části.

Získání názvu souboru a názvu adresáře aktuálně spouštěného souboru.

Chcete-li získat název souboru a název adresáře spuštěného souboru, použijte následující funkci v modulu os.path standardní knihovny.

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

Výsledek provedení.

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

Získání absolutní cesty ke spouštěnému souboru.

Pokud je pomocí __file__ získána relativní cesta, lze ji pomocí os.path.abspath() převést na absolutní cestu. Adresáře lze také získat jako absolutní cesty.

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

Výsledek provedení.

# 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

Pokud je v příkazu os.path.abspath() zadána absolutní cesta, bude vrácena tak, jak je. Pokud je tedy __soubor__ absolutní cestou, následující příkaz nevyvolá chybu.

  • os.path.abspath(__file__)

Čte další soubory na základě umístění aktuálně spouštěného souboru.

Pokud chcete číst další soubory na základě umístění (cesty) spouštěného souboru, spojte následující dva soubory pomocí os.path.join().

  • Adresář spouštěného souboru
  • Relativní cesta k souboru, který má být načten z běžícího souboru.

Pokud chcete číst soubor ve stejném adresáři jako soubor, který právě spouštíte, stačí zkombinovat název souboru.

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())

Výsledek provedení.

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

Horní úroveň je reprezentována symbolem „. \“. Můžete ji nechat tak, jak je, ale můžete použít os.path.normpath() k normalizaci cesty a odstranění přebytečného „. \“ a další znaky.

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())

Výsledek provedení.

# [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" !!

Přesun aktuálního adresáře do adresáře spouštěného souboru.

Pomocí funkce os.chdir() přesunete aktuální adresář do adresáře souboru spouštěného ve skriptu.

Vidíte, že je přesunut pomocí funkce os.getcwd().

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

Výsledek provedení.

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

Jakmile je aktuální adresář přesunut, není třeba jej při čtení souboru spojovat s adresářem spuštěného souboru. Stačí zadat cestu relativně k adresáři běžícího souboru.

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())

Výsledek provedení.

# [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" !!

Stejné zpracování lze provést bez ohledu na aktuální adresář za běhu.

Jak jsme si ukázali, je možné načítat soubory na základě umístění souboru skriptu nezávisle na aktuálním adresáři za běhu pomocí jedné z následujících metod.

  • Spojte adresář běžícího souboru a relativní cestu k souboru, který má být načten z běžícího souboru, pomocí os.path.join().
  • Přesun aktuálního adresáře do adresáře spouštěného souboru.

Je jednodušší přesunout aktuální adresář, ale pokud chcete poté číst nebo zapisovat další soubory, musíte samozřejmě počítat s tím, že aktuální adresář byl přesunut.

Výsledky předchozích příkladů jsou shrnuty níže.

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

Výsledek zadání absolutní cesty je následující.

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

Výsledek přesunu aktuálního adresáře v terminálu a spuštění stejného souboru skriptu je uveden níže. Je vidět, že stejný soubor lze přečíst, i když je spuštěn z jiného umístění.

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