142

In multiple open source projects, I have seen people do os.path.abspath(os.path.realpath(__file__)) to get the absolute path to the current file.

However, I find that os.path.abspath(__file__) and os.path.realpath(__file__) produce the same result. os.path.abspath(os.path.realpath(__file__)) seems to be a bit redundant.

Is there a reason people are using that?

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
hch
  • 6,030
  • 8
  • 20
  • 24

4 Answers4

169

For your stated scenario, there is no reason to combine realpath and abspath, since os.path.realpath actually calls os.path.abspath before returning a result (I checked Python 2.5 to Python 3.6).

  • os.path.abspath returns the absolute path, but does NOT resolve symlinks in its argument.
  • os.path.realpath will first resolve any symbolic links in the path, and then return the absolute path.

However, if you expect your path to contain a ~, neither abspath or realpath will resolve ~ to the user's home directory, and the resulting path will be invalid. You will need to use os.path.expanduser to resolve this to the user's directory.

For the sake of a thorough explanation, here are some results which I've verified in Windows and Linux, in Python 3.4 and Python 2.6. The current directory (./) is my home directory, which looks like this:

myhome
|- data (symlink to /mnt/data)
|- subdir (extra directory, for verbose explanation)
# os.path.abspath returns the absolute path, but does NOT resolve symlinks in its argument
os.path.abspath('./')
'/home/myhome'
os.path.abspath('./subdir/../data')
'/home/myhome/data'


# os.path.realpath will resolve symlinks AND return an absolute path from a relative path
os.path.realpath('./')
'/home/myhome'
os.path.realpath('./subdir/../')
'/home/myhome'
os.path.realpath('./subdir/../data')
'/mnt/data'

# NEITHER abspath or realpath will resolve or remove ~.
os.path.abspath('~/data')
'/home/myhome/~/data'

os.path.realpath('~/data')
'/home/myhome/~/data'

# And the returned path will be invalid
os.path.exists(os.path.abspath('~/data'))
False
os.path.exists(os.path.realpath('~/data'))
False

# Use realpath + expanduser to resolve ~
os.path.realpath(os.path.expanduser('~/subdir/../data'))
'/mnt/data'
MarcH
  • 18,738
  • 1
  • 30
  • 25
jobrad
  • 1,801
  • 2
  • 11
  • 7
  • 3
    Nice. To make your point your last example should be `os.path.realpath(os.path.expanduser('~/subdir/../data'))` – Arthur Apr 07 '18 at 16:13
  • 4
    Then also do not forget about os.path.expandvars if variables are used in a path – Slavenskij Apr 11 '18 at 06:55
  • 1
    `abspath(x)` always returns the same thing for a fixed `x` no matter the state of the filesystem. `realpath(x)` probes the filesystem for prefixes of `abspath(x)` and the return value of `realpath()` depends on what is found in the filesystem. – Joachim Wagner Nov 03 '22 at 10:58
85

os.path.realpath derefences symbolic links on those operating systems which support them.

os.path.abspath simply removes things like . and .. from the path giving a full path from the root of the directory tree to the named file (or symlink)

For example, on Ubuntu

$ ls -l
total 0
-rw-rw-r-- 1 guest guest 0 Jun 16 08:36 a
lrwxrwxrwx 1 guest guest 1 Jun 16 08:36 b -> a

$ python
Python 2.7.11 (default, Dec 15 2015, 16:46:19) 
[GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> from os.path import abspath, realpath

>>> abspath('b')
'/home/guest/play/paths/b'

>>> realpath('b')
'/home/guest/play/paths/a'

Symlinks can contain relative paths, hence the need to use both. The inner call to realpath might return a path with embedded .. parts, which abspath then removes.

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
kdopen
  • 8,032
  • 7
  • 44
  • 52
  • 13
    While this answer describes the difference between the two functions, it isn't true that the result of `realpath()` can contain `..` components and doesn't really answer the question of why you would use both; jobrad's answer is more accurate. – Miles Mar 24 '17 at 03:41
  • For Python 3.7 and windows, realpath don't understand substed drives So for a substed drive say P:\, having the source folder c:\MyFolder\Bla , realpath returns P:\ not c:\MyFolder\Bla. Anyone knowing how to get the "real" path? – Totte Karlsson Feb 17 '19 at 00:34
  • For me, `abspath` still followed symlinks if the current directory is a symlink. I only found this answer https://stackoverflow.com/questions/54665065/python-getcwd-and-pwd-if-directory-is-a-symbolic-link-give-different-results to stop this behavior. – Victor Sergienko May 03 '20 at 02:01
12

In the layman terms, if you are trying to get the path of a shortcut file, absolute path gives the complete path of the file present in the shortcut location, while realpath gives the original location path of the file.

Absolute path, os.path.abspath(), gives the complete path of the file which is located in the current working directory or the directory you mentioned.

Real path, os.path.realpath(), gives the complete path of the file which is being referred.

Eg:

file = "shortcut_folder/filename"
os.path.abspath(file) = "C:/Desktop/shortcut_folder/filename"
os.path.realpath(file) = "D:/PyCharmProjects/Python1stClass/filename"
ExtractTable.com
  • 762
  • 10
  • 20
0

In addition to the answers already provided, as of Python 3.8, os.path.realpath returns uppercase drive letters whereas os.path.abspath returns lowercase drive letters.

See this issue

R Loose
  • 28
  • 1
  • 6