为什么要同时使用os.path.abspath和os.path.realpath?

问题:为什么要同时使用os.path.abspath和os.path.realpath?

在多个开源项目中,我看到人们确实os.path.abspath(os.path.realpath(__file__))在获取当前文件的绝对路径。

但是,我发现os.path.abspath(__file__)os.path.realpath(__file__)产生相同的结果。os.path.abspath(os.path.realpath(__file__))似乎有点多余。

人们使用它是有原因的吗?

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?


回答 0

os.path.realpath 在支持它们的操作系统上取消引用符号链接。

os.path.abspath只需从路径中删除类似.和的东西,即可..提供从目录树的根到命名文件(或符号链接)的完整路径

例如,在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'

符号链接可以包含相对路径,因此需要同时使用两者。内部调用realpath可能会返回包含嵌入式..部件的路径,abspath然后将其删除。

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.


回答 1

对于您所陈述的场景,没有理由将realpath和abspath结合起来,因为os.path.realpath实际上是os.path.abspath在返回结果之前进行调用(我检查了Python 2.5到Python 3.6)。

  • os.path.abspath 返回绝对路径,但不解析其参数中的符号链接。
  • os.path.realpath 将首先解析路径中的任何符号链接,然后返回绝对路径。

但是,如果您期望路径包含a ~,则abspath或realpath都不会解析~到用户的主目录,并且结果路径将无效。您将需要使用os.path.expanduser将此解析到用户目录。

为了全面解释,以下是一些结果,这些结果已在Windows和Linux,Python 3.4和Python 2.6中进行了验证。当前目录(./)是我的主目录,如下所示:

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'

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'

回答 2

用外行术语来说,如果您尝试获取快捷方式文件的路径,则绝对路径将提供快捷方式位置中存在的文件的完整路径,而realpath则会提供文件的原始位置路径。

绝对路径os.path.abspath()提供位于当前工作目录或您提到的目录中的文件的完整路径。

实际路径os.path.realpath()给出了所引用文件的完整路径。

例如:

file = "shortcut_folder/filename"
os.path.abspath(file) = "C:/Desktop/shortcut_folder/filename"
os.path.realpath(file) = "D:/PyCharmProjects/Python1stClass/filename"

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"