Get the Path of the Current File (Script) in Python: __file__

Modified: | Tags: Python, File

In Python, you can use __file__ to get the path of the current script file (i.e., the .py file being executed). This is particularly useful when you need to read other files relative to the location of the script.

In Python 3.8 and earlier, __file__ returns the path exactly as it was specified when you ran the script using the python (or python3) command. If you use a relative path, __file__ returns it as a relative path; if you use an absolute path, it returns an absolute path.

However, starting with Python 3.9, __file__ always returns an absolute path, regardless of whether you executed the script using a relative or absolute path.

In the sample code throughout this article, assume you are working in the following directory. On Windows, you can use the dir command instead of pwd to check the current directory.

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

For information on how to get and change the current working directory in Python, refer to the following article:

Note that __file__ is not available in Jupyter Notebook (.ipynb). Regardless of where you launch the notebook, the working directory is set to the location of the .ipynb file by default. However, you can change it within your code using os.chdir().

__file__ stores the path of the current script file

Create a Python script named file_path.py in the data/src subdirectory.

import os

print('getcwd:      ', os.getcwd())
print('__file__:    ', __file__)
source: file_path.py

Run this script using the python (or python3) command.

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

You can use os.getcwd() to get the absolute path of the current working directory, and __file__ to get the path of the current script file.

In Python 3.8 and earlier, __file__ stores the path as given on the command line. In the example above, a relative path was used, so __file__ returns a relative path. If an absolute path were used instead, an absolute path would be returned.

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

In Python 3.9 and later, __file__ always returns an absolute path, regardless of how the script was executed.

In the following examples, add code to the same file_path.py file and run it from the same directory as above, using Python 3.7.

Note that if __file__ is an absolute path (which is always the case in Python 3.9 and later, or when using an absolute path in earlier versions), you can use the same code shown below to access files relative to the script's location. At the end of this article, you’ll also see what happens when running the script with an absolute path in Python 3.7.

Get the file name and directory of the current script file

You can use os.path.basename() and os.path.dirname() to get the file name and the directory that contains the current script file.

import os

print('basename:    ', os.path.basename(__file__))
print('dirname:     ', os.path.dirname(__file__))
source: file_path.py

The output is as follows:

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

To get only the name of the directory that contains the current script file (e.g., src in this case), you can use os.path.basename(os.path.dirname(__file__)).

Get the absolute path of the current script file

If __file__ is a relative path, you can convert it to an absolute path using os.path.abspath().

import os

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

The output is as follows:

# 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

Note that if __file__ is already an absolute path, os.path.abspath(__file__) will simply return it as-is. No error is raised in either case.

Read other files relative to the current file's location

To read other files relative to the script's location, use os.path.join() to combine the script’s directory path with the relative path to the target file.

If the file is in the same directory as the script file, you can simply pass its name.

import os

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())
source: file_path.py

The output is as follows:

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

In file paths, ../ refers to the parent directory. Although such paths work, you can clean them up using os.path.normpath() to eliminate unnecessary segments.

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())
source: file_path.py

The output is as follows:

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

For more details on reading files in Python, refer to the following article:

Change the working directory to the script's directory

You can use os.chdir() to change the current working directory to the directory where the current script file is located.

After changing the directory, you can confirm it using os.getcwd().

import os

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

The output is as follows:

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

If your working directory is the same as the script’s directory, you can use relative paths from the script to read other files.

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())
source: file_path.py

The output is as follows:

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

Read the same file regardless of the current working directory

By using __file__, you can reliably read the same file regardless of the current working directory.

As demonstrated above, there are two common approaches:

  • Join the __file__ directory with the file’s relative path using os.path.join().
  • Change the current working directory to the __file__ directory.

While changing the current directory is simpler, keep in mind that all subsequent file operations will be affected by the new working directory.

Here are the results from the examples so far:

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

And here are the results when running the script with an absolute path using the python3 command. As shown, the same file can still be read:

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

Even if you change the working directory in the terminal before running the script, it will still read the same file:

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

Related Categories

Related Articles