Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
Theory Relative paths are relative to the current working directory of the Python process. This can be checked from within Python using the os.getcwd function and set using the os.chdir function. ...
Answer
#1: Initial revision
## Theory Relative paths are relative to the *current working directory* of the Python process. This can be checked from within Python using the `os.getcwd` function and set using the `os.chdir` function. Whenever Python loads a module, a `__file__` attribute may be set on the resulting module object, giving the path to the source code file that the module is based on. (Normally, this will happen for all user code; but the attribute could be missing for built-in modules like `sys`, or it could be the name of a file containing compiled code if the module was implemented in C.) Within the code for that module, these attributes are just the global variables for that code. (There is also no `__file__` global variable available when using the REPL.) ## The technique Therefore, the code in `script.py` can simply check the `__file__` global variable to find a full path to `script.py`; and the *containing folder* for `script.py` can thus be determined by parsing that path, in any number of ways. The simplest way is to take advantage of the [`pathlib` standard library module (introduced in Python 3.4)](https://docs.python.org/3/library/pathlib.html), as shown in Moshi's answer. <section class="notice is-warning"> [In Python 3.9 and above](https://docs.python.org/3/whatsnew/3.9.html#other-language-changes), the same technique also works if `script.py` was run directly as a module. However, in Python 3.4 through 3.8, the `__file__` attribute [**will be a relative path**](https://docs.python.org/3.4/whatsnew/3.4.html#other-language-changes) if `script.py` was run directly as a module. (For example, if the command was `python script.py`, the `__file__` value will be simply `'script.py'`, and the Pathlib logic will produce just `'.'`.) As a result, this technique *will break if the current working directory has changed* between the time the script was started and the time that the path taken from `__file__` is used. To avoid this issue, make sure to determine `__file__` immediately, compute an absolute path immediately, and store that path until needed: ```python from pathlib import Path # when the script starts here = Path(__file__).parent.absolute() # later, possibly after an `os.chdir` call with open(here / 'data.txt') as file: data = file.read() ``` </section> ## Legacy support (Python 3.3 and earlier) In older versions of Python, `__file__` is still documented to be present on `module` objects (and thus be available as a global variable), with the same purpose. [However, it is not guaranteed to be an absolute path](https://mail.python.org/pipermail/python-dev/2010-February/097461.html). (For an absolute import, it will depend upon the entry in `sys.path` that was used for the import.) Further, `pathlib` is not available. Thus, the necessary code might look like: ```python import os # when the script starts here = os.path.split(os.path.abspath(__file__))[0] # later, possibly after an `os.chdir` call with open(scriptFolder / 'data.txt') as file: data = file.read() ``` Here, `os.path.abspath` creates an absolute path, and `os.path.split` splits it into two parts - the "path" (i.e., to the containing folder) and the filename itself. ---- Credit to kindall and wim [on Stack Overflow](https://stackoverflow.com/a/7116925) for the corresponding research about the semantics of `__file__`. kindall uncovered the legacy semantics, which agf then described in that answer; later, wim edited to supply the updated semantics in Python 3.4+.