下面的代码将不会加入,在调试时该命令不会存储整个路径,而只会存储最后一个条目。

os.path.join('/home/build/test/sandboxes/', todaystr, '/new_sandbox/')


当我测试此命令时,它仅存储/new_sandbox/部分的代码。

#1 楼

后面的字符串不应以斜杠开头。如果它们以斜杠开头,则它们被视为“绝对路径”,并且它们之前的所有内容都将被丢弃。

在Python文档中引用os.path.join


如果组件是绝对路径,则所有先前的组件都将被丢弃,并且连接将从绝对路径组件继续。


在Windows上请注意,与驱动器号有关的行为似乎与早期的Python版本相比已发生变化:


在Windows上,遇到绝对路径组件(例如r'\foo')时,不会重置驱动器号。如果组件包含驱动器号,则会丢弃所有先前的组件,并重置驱动器号。请注意,由于每个驱动器都有一个当前目录,因此os.path.join("c:", "foo")代表相对于驱动器C:c:foo)上当前目录的路径,而不是c:\foo


评论


-1:任何字符串都不应包含“ /”。 os.path.join的一个重点是防止在路径中放置任何斜线。

– S.Lott
09-12-22在12:29

当然,str.join()的问题在于它不会消除双斜杠。我认为这是使用os.path.join的人们的主要目的。例如'/'.join(['/etc/','/ conf'])导致三个斜杠:'/ etc /// conf'

– Dustin Rasener
2012年7月31日14:03

@DustinRasener您可以使用os.path.normpath来实现该目标。

–加雷斯·拉蒂(Gareth Latty)
2012-10-28 17:48

不知道人们为什么对os.path.join行为感到沮丧。在其他语言中,等效的路径连接库/方法的行为完全相同。更安全,更有意义。

–唐·奇德尔(Don Cheadle)
2014年12月4日在17:41

这令人沮丧,因为它是隐式魔术,这与“显式优于隐式”的基本启发式相反。是的。语言设计师可能会认为他们了解得更多,但是存在明显且明显安全的理由,偶尔需要这样做。现在我们不能。这就是为什么我们不能拥有美好的事物。

– Cecil咖喱
15年8月18日在5:54

#2 楼

os.path.join()的思想是使您的程序跨平台(linux / windows / etc)。

即使有一个斜杠也会破坏它。

所以这仅在使用时有意义带有某种参考点,例如
os.environ['HOME']os.path.dirname(__file__)

#3 楼

os.path.join()可以与os.path.sep结合使用,以创建绝对路径而不是相对路径。

os.path.join(os.path.sep, 'home','build','test','sandboxes',todaystr,'new_sandbox')


评论


使用os.path.sep作为构建绝对​​路径的第一个元素比这里的其他答案要好!使用os.path而不是基本的str方法的全部目的是避免编写/。将每个子目录作为新参数并删除所有斜杠也很好。最好检查一下今天是否没有以斜杠开头! ;)

– snooze92
2014年1月23日在8:59



这也适用于Windows(python 2.7.6)。它不干扰“ C:\”,并加入了子目录。

– rickfoosusa
2015年2月2日在21:22

#4 楼

除了引用根目录时,不要在路径组件的开头使用正斜杠:

os.path.join('/home/build/test/sandboxes', todaystr, 'new_sandbox')


另请参见:http://docs.python.org/ library / os.path.html#os.path.join

#5 楼

为了帮助理解为什么这种令人惊讶的行为并不完全可怕,请考虑一个将配置文件名作为参数的应用程序:

config_root = "/etc/myapp.conf/"
file_name = os.path.join(config_root, sys.argv[1])


如果使用以下命令执行该应用程序:

$ myapp foo.conf


将使用配置文件/etc/myapp.conf/foo.conf

但是请考虑使用以下方法调用应用程序会发生什么情况:

$ myapp /some/path/bar.conf


然后myapp应该使用/some/path/bar.conf上的配置文件(而不是/etc/myapp.conf/some/path/bar.conf或类似的文件)。

可能不是很好,但是我相信这是为了绝对路径行为。

评论


谢谢!在阅读您的答案之前,我一直讨厌这种行为!它记录在docs.python.org/3.5/library/os.path.html#os.path.join中,但没有动机。

– Eli_B
17年9月7日在11:59



这一刻,当您确切需要解决方案时,许多人认为这很糟糕。

– Ashrasmun
19年9月4日在20:33

要不同意,这是完全可怕的。在这种情况下,您不应使用朴素的sys.argv输入来确定是否在config_root之前添加。所有os.path.join应该与联接文件路径元素有关。

–user5359531
20年9月1日于20:53

#6 楼

这是因为您的'/new_sandbox/'/开头,因此被认为是相对于根目录的。卸下前导/

#7 楼

尝试结合使用split("/")*来查找具有现有联接的字符串。

import os

home = '/home/build/test/sandboxes/'
todaystr = '042118'
new = '/new_sandbox/'

os.path.join(*home.split("/"), todaystr, *new.split("/"))





如何工作...

split("/")将现有路径转换为列表:['', 'home', 'build', 'test', 'sandboxes', '']

列表前面的*将列表中的每个项目分解成自己的参数

评论


这将其变成相对路径而不是绝对路径

–user5359531
20年9月1日21:00

#8 楼

为了使您的功能更易于移植,请按以下方式使用它:

os.path.join(os.sep, 'home', 'build', 'test', 'sandboxes', todaystr, 'new_sandbox')




os.path.join(os.environ.get("HOME"), 'test', 'sandboxes', todaystr, 'new_sandbox')


#9 楼

仅尝试使用new_sandbox

os.path.join('/home/build/test/sandboxes/', todaystr, 'new_sandbox')


#10 楼

这样做,没有太多的斜杠

root="/home"
os.path.join(root,"build","test","sandboxes",todaystr,"new_sandbox")


#11 楼

请注意,如果您使用os.path.join()来包含已经包含点的扩展名,则类似的问题也会咬您,使用os.path.splitext()时,扩展名会自动出现。在此示例中:即使extension可能是.jpg,您最终还是得到一个名为“ foobar”的文件夹,而不是一个名为“ foobar.jpg”的文件。为避免这种情况,您需要单独添加扩展名:

components = os.path.splitext(filename)
prefix = components[0]
extension = components[1]
return os.path.join("avatars", instance.username, prefix, extension)


#12 楼

您可以strip '/'

>>> os.path.join('/home/build/test/sandboxes/', todaystr, '/new_sandbox/'.strip('/'))
'/home/build/test/sandboxes/04122019/new_sandbox'


#13 楼

我建议从第二个及以下字符串中删除字符串os.path.sep,以防止将它们解释为绝对路径:

first_path_str = '/home/build/test/sandboxes/'
original_other_path_to_append_ls = [todaystr, '/new_sandbox/']
other_path_to_append_ls = [
    i_path.strip(os.path.sep) for i_path in original_other_path_to_append_ls
]
output_path = os.path.join(first_path_str, *other_path_to_append_ls)


#14 楼

os.path.join("a", *"/b".split(os.sep))
'a/b'


完整版本:

import os

def join (p, f, sep = os.sep):
    f = os.path.normpath(f)
    if p == "":
        return (f);
    else:
        p = os.path.normpath(p)
        return (os.path.join(p, *f.split(os.sep)))

def test (p, f, sep = os.sep):
    print("os.path.join({}, {}) => {}".format(p, f, os.path.join(p, f)))
    print("        join({}, {}) => {}".format(p, f, join(p, f, sep)))

if __name__ == "__main__":
    # /a/b/c for all
    test("\a\b", "\c", "\") # optionally pass in the sep you are using locally
    test("/a/b", "/c", "/")
    test("/a/b", "c")
    test("/a/b/", "c")
    test("", "/c")
    test("", "c")


评论


如果os.sep实际上是“ \”怎么办?然后,您的第一个示例变为os.path.join(“ a”,*“ / b” .split(“ \\”)),产生“ / b” ...我怀疑这是预期的结果。

– NichtJens
20-5-16在22:13



更新-我想您必须给出提示,因为您在本地使用的路径sep与运行的操作系统无关

–尼尔·麦吉尔(Neil McGill)
20年5月17日在1:54

是。另一种选择是,可以在两个常用选项上分开使用……但是其他一些操作系统可以提供第三个。

– NichtJens
20-05-17在9:30