Python os.path.relpath 行为

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17506552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 08:22:07  来源:igfitidea点击:

Python os.path.relpath behavior

pythonpathos.path

提问by jveldridge

I have a directory barinside a directory foo, with file foo_file.txtin directory fooand file bar_file.txtin directory bar; i.e.

我有一个目录bar的目录里面foo,使用文件foo_file.txt目录foo和文件bar_file.txt目录bar; IE

computer$ ls
foo/
computer$ ls foo/
bar/  foo_file.txt
computer$ ls foo/bar/
bar_file.txt

Using the python os.path.relpathfunction, I expect:

使用 python os.path.relpath函数,我期望:

os.path.relpath('foo/bar/bar_file.txt', 'foo/foo_file.txt')

to give me:

给我:

'bar/bar_file.txt'

However, it actually gives me:

然而,它实际上给了我:

'../bar/bar_file.txt'

Why is this? Is there an easy way to get the behavior I want?

为什么是这样?有没有一种简单的方法可以获得我想要的行为?

EDIT: This is on Linux with Python 2.7.3

编辑:这是在带有 Python 2.7.3 的 Linux 上

采纳答案by Ignacio Vazquez-Abrams

os.path.relpath()assumes that its arguments are directories.

os.path.relpath()假设它的参数是目录。

>>> os.path.join(os.path.relpath(os.path.dirname('foo/bar/bar_file.txt'),
        os.path.dirname('foo/foo_file.txt')),
        os.path.basename('foo/bar/bar_file.txt'))
'bar/bar_file.txt'

回答by Ignacio Vazquez-Abrams

os.path.relpath(arg1, arg2) 

will give the relative path of arg2 from the directory of arg1. In order to get from arg2 to arg1 in your case, you would need to cd up one directory(..), go the bar directory(bar), and then the bar_file.txt. Therefore, the relative path is

将从 arg1 的目录中给出 arg2 的相对路径。在您的情况下,为了从 arg2 到 arg1,您需要 cd 一个目录 (..),转到 bar 目录 (bar),然后转到 bar_file.txt。因此,相对路径为

../bar/bar_file.txt

回答by Connor

relpathhas unexpected behavior. It treats all elements of a path as though it is a directory. So, in the path:

relpath有意外行为。它将路径的所有元素视为目录。所以,在路径中:

/path/to/a/file.txtfile.txtis treated like a directory as well.

/path/to/a/file.txtfile.txt也被视为目录。

This means that when you run relpathon two paths, say,

这意味着当你relpath在两条路径上运行时,比如说,

>>> from os.path import relpath
>>> relpath('/path/to/dest/file.txt', '/path/to/origin/file.txt')
'../../dest/file.txt'

This is incorrect. The true relative path from directory origin to dest is '../dest/file.txt'

这是不正确的。从目录 origin 到 dest 的真正相对路径是'../dest/file.txt'

This gets especially frustrating if you're trying to create symlinks and they end up being malformed.

如果您尝试创建符号链接并且它们最终格式不正确,这会特别令人沮丧。

Solution

解决方案

To fix the problem, we must first find out if the path points to a file, if not we can do the comparison as usual, otherwise we need to remove the filename from the end, do the comparison with only directories, and then add the file back to the end.

要解决这个问题,我们首先要找出路径是否指向一个文件,如果不是我们可以照常进行比较,否则我们需要从末尾去掉文件名,只与目录进行比较,然后添加文件回到最后。

Note that this only works if you actually have these files created on your system, python must access the filesystem to find the node types.

请注意,这仅在您实际在系统上创建了这些文件时才有效,python 必须访问文件系统以查找节点类型。

import os

def realrelpath(origin, dest): 
    '''Get the relative path between two paths, accounting for filepaths'''

    # get the absolute paths so that strings can be compared
    origin = os.path.abspath(origin) 
    dest = os.path.abspath(dest) 

    # find out if the origin and destination are filepaths
    origin_isfile = os.path.isfile(origin)
    dest_isfile = os.path.isfile(dest)

    # if dealing with filepaths, 
    if origin_isfile or dest_isfile:
        # get the base filename
        filename = os.path.basename(origin) if origin_isfile else os.path.basename(dest)
        # in cases where we're dealing with a file, use only the directory name
        origin = os.path.dirname(origin) if origin_isfile else origin
        dest = os.path.dirname(dest) if dest_isfile else dest 
        # get the relative path between directories, then re-add the filename
        return os.path.join(os.path.relpath(dest, origin), filename)  
    else:
        # if not dealing with any filepaths, just run relpath as usual
        return os.path.relpath(dest, origin)   


To get the real relative path from directory origin to dest, run:

要获取从目录 origin 到 dest 的真实相对路径,请运行:

>>> relrealpath('/path/to/origin/file.txt', '/path/to/dest/file.txt')
'../dest/file.txt'

I flipped the argument order because in my brain it makes more sense to say, "I want to know the relative path to take from arg1 to get to arg2", the standard relpathimplementation has it backwards (probably because that's how UNIX does it).

我颠倒了参数顺序,因为在我的大脑中,说“我想知道从 arg1 到 arg2 的相对路径”更有意义,标准relpath实现将其倒置(可能是因为 UNIX 就是这样做的)。

This need to access the filesystem is the real reason that relpathhas such strange behavior. Filesystem calls are expensive, so python leaves it up to you to know whether you're dealing with a file or with a directory and only performs string operations on the path you provide.

这种访问文件系统的需要是relpath具有这种奇怪行为的真正原因。文件系统调用是昂贵的,所以 python 由你决定你是在处理文件还是目录,并且只在你提供的路径上执行字符串操作。

Note: There is probably a way to make the realrelpathfunction a bit more efficient. For example, I'm not sure if the abspathcalls are necessary, or if they could be bundled with the os.path.isfilechecks with a syscall that returns more information. I welcome improvements.

注意:可能有一种方法可以使realrelpath函数更高效。例如,我不确定这些abspath调用是否必要,或者它们是否可以与os.path.isfile返回更多信息的系统调用的检查捆绑在一起。我欢迎改进。