Diference between os.getcwd() and os.path.dirname(__file__)
In a previous project, I used the first version of the following two lines. Now that I found getcwd() I thought this would be the shorter alternative.
print(os.path.dirname(__file__)) # D:/Personal_Software/my_project
print(os.getcwd()) # D:\Personal_Software\my_project
I already read this post, but the thing I'm curious about is the use of "/" vs. "\". I'm using Windows 10 if that's relevant.
-
__file__
is filename provided to Python, exactly as it was provided. -
os.path.dirname(__file__)
is usually the directory in which a script is located. (But not always, as you'll see below.) -
os.path.dirname(os.path.realpath(__file__))
is the directory in which the script is located. -
os.getcwd()
is the current directory.
The current directory has nothing to do with where the script is located. It's a per-process path used to resolve relative paths.
/tmp/ikegami/a.py
:
#!/usr/bin/python3
import os
print(__file__)
print(os.path.dirname(__file__))
print(os.path.dirname(os.path.realpath(__file__)))
print(os.getcwd())
[~]$ bin/a # A symlink to /tmp/ikegami/a.py
bin/a # The path provided to python3.
bin # NOT the directory in which the script is located.
/tmp/ikegami # The directory in which the script is located.
/home/ikegami # The current directory (~ = /home/ikegami)
[~]$ /tmp/ikegami/a.py
/tmp/ikegami/a.py # The path provided to python3.
/tmp/ikegami # The parent of the path provided to python3.
/tmp/ikegami # The directory in which the script is located.
/home/ikegami # The current directory (~ = /home/ikegami)
[~]$ cd /tmp/ikegami
[/tmp/ikegami]$ ./a.py
./a.py # The path provided to python3.
. # The parent of the path provided to python3.
/tmp/ikegami # The directory in which the script is located.
/tmp/ikegami # The current directory
(Those test were run on a Linux machine because I don't have python installed on this Windows machine. You'll get similar results on Windows.)
the thing I'm curious about is the use of "/" vs. "\".
For at least as long as Windows has been an operating system (WinNT, 1993; Win95, 1995), Windows has accepted both \
and /
as the directory separator.[1][2] These are equivalent. \
is the canonical separator (the one that's preferred for consistency), but /
works just as well. This was the case for DOS before that too.
It appears that your program was launched using python3 D:/Personal_Software/my_project/file.py
. __file__
contains the exact path provided to Python, and dirname(__file__)
simply removes the last bit.
os.getcwd()
, on the other hand, receives the current directory from the OS, and the OS probably returns the canonical form of the current directory.
-
You can even use
//
for UNC paths (//server/share
) and similar (//?/...
,//./...
, etc). -
Contrary to claims that have been made, this is the case for system calls (i.e. the Win32 API), this is the case in Explorer ("My Computer", "File Explorer", "Save As" dialogs, etc), this is the case for the Power Shell (e.g.
dir "c:/bin"
,c:/bin/myprog
), and this is case in the Windows console (e.g.c:/bin/myprog
).Caveat: Some specific Windows console commands (e.g.
dir
) requires paths with/
to be in quotes (e.g.dir "c:/"
) because/
signals the start of an option to them.
There is a difference, though you wouldn't be able to tell from a single script.
__file__
is the full filename of a loaded module or script, so getting the parent directory of it with os.path.dirname(__file__)
gets you the directory that script is in.
Note: on Linux (and similar OSes), such a filename can be a symbolic link to the actual file which may reside somewhere else. You can use os.path.realpath()
to resolve through any such links, if needed, although you can typically use the symlink equivalently. On Windows these are less common, but similarly, you can resolve symbolic links through realpath()
.
os.getcwd()
gets you the current working directory. If you start a script from the directory the script is in (which is common), the working directory will be the same as the result from the call from os.path.dirname(__file__)
.
But if you start the script from another directory (i.e. python d:\some\path\script.py
), or if you change the working directory during the script (e.g. with os.chdir()
), the current working directory has changed, but the directory part of the script filename has not.
So, it depends on what you need:
- Need the directory your script file is in? Use
os.path.dirname(__file__)
- Need the directory your script is currently running in? use
os.getcwd()
You'll see /
in some results and \
in others. Sadly, MS Windows uses \
to separate parts of a path (e.g. C:\Program Files\App\
), while pretty much all other operating systems use /
(e.g. /home/user/script.py
)
Python will often convert those automatically, so you can use paths like C:/Program Files/App
in Python on Windows as well, but it tends to be a good idea to be safe and use os.path.sep
.
Note: if you're on Python 3, you may be better off just using pathlib
's Path
instead of os.path
. It automatically resolves symbolic links (although you can still resolve to the link if you prefer) and has other nice conveniences as well.