Frank Zalkow
Frank Zalkow

Reputation: 3930

__file__ returns a wrong relative path after changing the current working directory in Python 3.7

Under certain circumstances, the variable __file__ is relative (see this stackoverflow question for details). If the variable is relative and one changes the current working directory, __file__ doesn't change accordingly. As a result, the relative path is invalid.

Please see this minimal example:

import os


if __name__ == '__main__':
    filepath = __file__
    filepath_real = os.path.realpath(filepath)
    print('pwd', os.getcwd())
    print('relative', filepath, os.path.exists(filepath))
    print('absolute', filepath_real, os.path.exists(filepath_real))

    os.chdir('..')
    print('... changing the working directory ...')

    filepath = __file__
    filepath_real = os.path.realpath(filepath)
    print('pwd', os.getcwd())
    print('relative', filepath, os.path.exists(filepath))
    print('absolute', filepath_real, os.path.exists(filepath_real))

Suppose this file is located at /home/user/project/script.py. If I execute script.py, this is the output:

$ cd /home/user/project/
$ python script.py
pwd /home/user/project
relative test.py True
absolute /home/user/project/test.py True
... changing the working directory ...
pwd /home/user
relative test.py False
absolute /home/user/test.py False

Is it possible to get a correct __file__ path (one that exists according to os.path.exists) after changing the working directory in Python 3.7? I am aware that this issue does not exist in higher Python versions (such as 3.9), where __file__ always returns an absolute path.

Upvotes: 1

Views: 1726

Answers (1)

gftea
gftea

Reputation: 568

get the __file__ path at the beginning of the python file, which ensure that you get the path when the file is imported before you calling the function.

python interpreter evaluate the file line by line in sequence, file will be evaulated only once by interpreter even you import the file multiple times , so first time the file is imported, all codes of the file have been evaluated and you path vallue is assigned.

you will only have issue when you change working dir, then force reload the file programmatically and reimport the file, then the value will be changed, otherwise it stays constant duing life time of your program.

EDIT

below example to show the after you import the module, the __file__ does not change after you change the working dir

import os


if __name__ == '__main__':
    filepath = os.__file__
    filepath_real = os.path.realpath(filepath)
    print('pwd', os.getcwd())
    print('relative', filepath, os.path.exists(filepath))
    print('absolute', filepath_real, os.path.exists(filepath_real))

    os.chdir('..')
    print('... changing the working directory ...')

    filepath = os.__file__
    filepath_real = os.path.realpath(filepath)
    print('pwd', os.getcwd())
    print('relative', filepath, os.path.exists(filepath))
    print('absolute', filepath_real, os.path.exists(filepath_real))

output

pwd /home/gftea/repo/jackygao/eiffel-system/utils
relative /usr/lib/python3.8/os.py True
absolute /usr/lib/python3.8/os.py True
... changing the working directory ...
pwd /home/gftea/repo/jackygao/eiffel-system
relative /usr/lib/python3.8/os.py True
absolute /usr/lib/python3.8/os.py True

Upvotes: 0

Related Questions