pythonpython-importrelative-import

Is it bad practice to change the working directory to import from different files?


Relative imports do not work in interactive python sessions, but I could change the directory os.chdir('..') then import module_in_parent and then go back os.chdir('original_directory'). Or do the same for a parallel directory.

Would that be considered bad practice, and if so, why? (I haven't really seen it used, but ran into the problem multiple times myself.)

I have used some scripts and utility functions for an experiment and would like to keep the folder-structure as is, but also reuse some of the scripts for a new experiment.

Edit: Here is an example with a folder structure:

project/
├── experiment
│   ├── main.py
│   └── utils
│       └── utils_functions.py
└── new_experiment
    └── main2_.py

Where I want to import utils_functions from main2.py. And I don't want to change anything in experiment.

@Random Davis: In the example above, I get the error ImportError: attempted relative import beyond top-level package with importlib.

I am not working on a program with a single entry point, but rather doing some data analysis, where I use multiple short scripts to modify and visualize the data.


Solution

  • It is easy enough to add your directories to the search path - actually, I think it is easier than changing the directory.

    While changing the directoy in this way would be very, very, very bad in a running program, in an interactive session it is just cumbersome - so, ok, you did it once, it did what you needed, you did that twice - fine...but repeating it over and over is just a no.

    The directories where Python look for files to import is a plain list of strings, and it is trivial to add the directories you want there, in the priority order you want:

    >>> from pathlib import Path; import os, sys
    >>> sys.path.insert(0, str(Path(os.getcwd()).parent())
    

    will insert the parent dir in the Python path for import. without changing the working directory. (It can be removed from the list, afterwards, as well). Also, the pathlib.Path juggling is just to be able to use .parent - one could just do sys.path.insert(0, os.getcwd() + "/..") - (and the insert(0, ...) is just the insert method of regular lists, putting the new path at the position 0)