Answers:
后面的字符串不应以斜杠开头。如果它们以斜杠开头,那么它们将被视为“绝对路径”,并且丢弃它们之前的所有内容。
如果组件是绝对路径,则所有先前的组件都将被丢弃,并且连接将从绝对路径组件继续。
请注意,在Windows上,与驱动器号有关的行为与早期的Python版本相比似乎有所变化:
在Windows上,
r'\foo'
遇到绝对路径组件(例如)时,不会重置驱动器号。如果某个组件包含驱动器号,则会丢弃所有先前的组件,并重置驱动器号。请注意,由于每个驱动器都有一个当前目录,因此os.path.join("c:", "foo")
表示相对于驱动器C:
(c:foo
)上当前目录的路径,而不是c:\foo
。
os.path.normpath
用来实现该目标。
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方法的全部目的是避免编写/
。将每个子目录作为新参数并删除所有斜杠也很好。确保使用todaystr
不以斜杠开头的支票可能是一个好主意!;)
除了在引用根目录时,不要在路径组件的开头使用正斜杠:
os.path.join('/home/build/test/sandboxes', todaystr, 'new_sandbox')
另请参见:http : //docs.python.org/library/os.path.html#os.path.join
为了帮助理解为什么这种令人惊讶的行为并不完全可怕,请考虑接受配置文件名作为参数的应用程序:
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.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
我建议从第二个和后面的字符串中删除字符串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)
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.path.join("a", *"/b".split("\\"))
,它产生"/b"
...我怀疑这是预期的结果。