为什么os.path.join()在这种情况下不起作用?

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

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

当我测试这个时,它只存储代码的/new_sandbox/部分。

613397 次浏览

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

引用os.path.join的Python文档:

如果一个组件是一个绝对路径,那么之前的所有组件都将被丢弃,连接将继续从绝对路径组件开始。

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

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

不要在路径组件的开头使用正斜杠,除非指向根目录:

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

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

只尝试new_sandbox

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

这是因为你的'/new_sandbox/'/开头,因此被认为是相对于根目录的。删除前导/

像这样,去掉多余的斜杠

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

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

一刀就毁了它。

所以它只有在与某种参考点一起使用时才有意义,比如 os.environ['HOME']os.path.dirname(__file__).

os.path.join()可以和os.path.sep一起使用来创建一个绝对路径,而不是相对路径。

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

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

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或类似文件)。

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

为了让你的函数更可移植,可以这样使用它:

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

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

请注意,如果使用os.path.join()来包含一个已经包含点的扩展,就会出现类似的问题,这是在使用os.path.splitext()时自动发生的情况。在这个例子中:

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

即使extension可能是.jpg,你最终会得到一个名为“foobar”的文件夹,而不是一个名为“foobar.jpg”的文件。为了防止这种情况,你需要单独追加扩展:

return os.path.join("avatars", instance.username, prefix) + extension

对于已有连接的字符串,尝试split("/")*的组合。

import os


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


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

< br >

它是如何工作的…

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

列表前面的*将列表的每一项各自的参数分开

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")

你可以strip '/':

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

我建议从第二个和下面的字符串中剥离字符串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)
问题是你的笔记本电脑可能运行windows。Window烦人地使用后斜杠而不是前斜杠'/'。使你的程序跨平台(linux/windows/etc)。 如果你想要os.path.join正确地处理斜杠,你不应该在路径中提供任何斜杠(向前或向后)。你应该使用:

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


或者抛出一些Path(__file__).resolve().parent(当前文件的父路径)或任何东西,以便在os.path.join中不使用任何斜杠

请参考下面的代码片段来理解os.path.join(a, b)

a = '/home/user.name/foo/'
b = '/bar/file_name.extension'


print(os.path.join(a, b))
>>> /bar/file_name.extension

a = '/home/user.name/foo'
b = '/bar/file_name.extension'
print(os.path.join(a, b))
>>> /bar/file_name.extension

但是,当

a = '/home/user.name/foo/'
b = 'bar/file_name.extension'


print(os.path.join(a, b))
>>> /bar/file_name.extension

a = '/home/user.name/foo'
b = 'bar/file_name.extension'
print(os.path.join(a, b))
>>> /home/user.name/foo/bar/file_name.extension