os.path.join()的行为是否正常?

2 投票
2 回答
668 浏览
提问于 2025-04-18 10:50

示例1中,path2以'/'开头,结果是 /dir2/dir3/(缺少了path1)

path1='/Volumes/disk1/'
path2='/dir2/dir3/'
print os.path.join(path1,path2)

示例2中,path2没有以'/'开头,结果是正确的 /Volumes/disk1/dir2/dir3/

path1='/Volumes/disk1/'
path2='dir2/dir3/'
print os.path.join(path1,path2)

问题:我原以为os.path.join()的目的就是让我们避免繁琐的工作,比如检查文件路径是mac、windows还是linux:一个命令就能搞定。但现在如果我还得去注意path2是以'/'(或者'\')开头还是不开头,这让我之前的希望都破灭了,还要增加很多额外的代码……那有什么解决办法吗?我不想做这种麻烦的事情:

if path2 and path2.replace('\\','/')[1:] and path2.replace('\\','/').startswith('/'):
    path2=path2[1:]

2 个回答

1

直接来自文档的内容,

智能地连接一个或多个路径组件。如果任何组件是绝对路径,那么之前的所有组件(在Windows上,包括之前的驱动器字母,如果有的话)都会被丢弃,然后继续连接。

你看到这样的行为是因为你传入了一个绝对路径(以'/'开头的路径)。你的程序需要能够处理这两者之间的区别,如果是程序自己生成路径,确保在需要绝对路径时生成绝对路径,在需要相对路径时生成相对路径。

为什么这很有用的解释

考虑以下情况。我有一个命令行界面,要求用户指定一个文件输出的路径。在我的文档中,我这样说明:

path: Path to an output file. If relative, will be placed inside ~/Documents.

现在在我的代码中,我只需要这样做:

out_path = os.path.join('~','Documents', path)

现在out_path将始终包含正确的路径。如果用户指定volume_1/output.txt,文件将会出现在~/Documents/volume_1/output.txt中。如果他们指定/mnt/volume_1/output.txt,文件将会出现在/mnt/volume_1/output.txt中,因为绝对路径会覆盖我们提供的默认相对路径。

1

为了避免检查路径分隔符的麻烦,你需要在开始时就不使用它们,或者在传递给 os.path.join() 之前完全去掉它们。下面的代码展示了三种可以做到这一点的方法(你可以通过这个在线示例来试试)。

单独的目录

import os
print os.path.join('Volumes', 'disk1', 'dir2', 'dir3')

分割路径然后合并

path1 = '/Volumes/disk1/'
path2 = '/dir2/dir3/'

import os
# this will convert to the same as above:
# i.e., os.path.join('Volumes', 'disk1', 'dir2', 'dir3')
print os.path.join(*(path1.split(os.sep) + path2.split(os.sep)))

自定义合并函数

使用上面的代码,你可以写一个自定义的 join() 函数,适用于单个或多个路径字符串:

def join(*paths):
    import os
    return os.path.join(*[part for path in paths for part in path.split(os.sep)])

path1 = '/Volumes/disk1/'
path2 = '/dir2/dir3/'

print join(path1, path2)

输出:

'Volumes/disk1/dir2/dir3'

撰写回答