I use the following function for opening files in Python:
def file_path(relative_path):
folder = os.path.dirname(os.path.abspath(__file__))
path_parts = relative_path.split("/")
new_path = os.path.join(folder, *path_parts)
return new_path
I call it with a relative path, like this:
with open(file_path("my_files/zen_of_python.txt")) as f:
zop = f.read()
I like it because you can use a relative path works no matter where the Python script is executed from:
folder = os.path.dirname(os.path.abspath(__file__))
gets the absolute path to the folder holding the python script.os.path.join(folder, *path_parts)
gets an os-independent path to the file to open.
To further explain, let's say I have the following folder structure:
- parent_folder - example.py - my_files - zen_of_python.txt
If example.py looks like this:
with open("my_files/zen_of_python.txt") as f:
zop = f.read()
Then I have to run example.py from the parent_folder directory or else it won't find my_files/zen_of_python.txt
.
But if I open my_files/zen_of_python.txt
using the file_path()
function shown above, I can run example.py from anywhere.
One downside as @infinitezero pointed out is that you can't use an absolute path, but for my purposes, that's okay for my purposes. The script is self-contained. I'm not passing in external files when I run it.
Can anyone see any downside to this? Or does anyone have a more Pythonic way of accomplishing the same thing?
2 Answers 2
Your code represents a well-known pattern. In Java, files like this are called resource files and they are delivered together with the code in a .jar file (which is essentially a .zip file).
As pointed out in a comment, you cannot use your code with absolute paths. This is good since the entire purpose of the code is to find a resource relative to the source code that needs this resource.
The call to abspath
looks redundant to me. I'm assuming that __file__
is already an absolute path. You may want to check the documentation about it.
A downside of your function is that you have to define it in each file that wants to open relative files since it uses __file__
. You cannot import
that function, as it is now.
-
\$\begingroup\$ If you execute a script using a relative path (e.g.,
python my_file.py
), then__file__
will be relative. You're right that a downside is that you cannot import the function unless it's in the same directory. You could fix this by accepting__file__
as a 2nd param. \$\endgroup\$Webucator– Webucator2020年02月05日 16:14:46 +00:00Commented Feb 5, 2020 at 16:14
If using just os.path
, this looks almost perfect.
- Move
folder
into the global scope, as there's no point not to. It means that the function can be made simpler - as it's now split into two seperate entities.
FOLDER = os.path.dirname(os.path.abspath(__file__))
def file_path(relative_path):
return os.path.join(folder, *relative_path.split("/"))
It would be better if you used pathlib
. This is the modern version of os.path
. If you do, then I would recomend just making folder
as there would be no need for the function.
FOLDER = pathlib.Path(__file__).resolve().parent
with (FOLDER / 'my_files/zen_of_python.txt').open() as f:
...
Here are some examples of running it on Windows in Python 3.8.
>>> import pathlib
>>> FOLDER = pathlib.Path('foo')
>>> FOLDER / 'bar/baz' # Unix style
WindowsPath('foo/bar/baz')
>>> FOLDER / 'bar\\baz' # Windows style
WindowsPath('foo/bar/baz')
>>> FOLDER / 'bar' / 'baz' # Pathlib style
WindowsPath('foo/bar/baz')