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

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

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

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

当我对此进行测试时,它仅存储/new_sandbox/部分代码。

The below code will not join, when debugged the command does not store the whole path but just the last entry.

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

When I test this it only stores the /new_sandbox/ part of the code.


回答 0

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

Python文档os.path.join引用

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

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

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

The latter strings shouldn’t start with a slash. If they start with a slash, then they’re considered an “absolute path” and everything before them is discarded.

Quoting the Python docs for os.path.join:

If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.

Note on Windows, the behaviour in relation to drive letters, which seems to have changed compared to earlier Python versions:

On Windows, the drive letter is not reset when an absolute path component (e.g., r'\foo') is encountered. If a component contains a drive letter, all previous components are thrown away and the drive letter is reset. Note that since there is a current directory for each drive, os.path.join("c:", "foo") represents a path relative to the current directory on drive C: (c:foo), not c:\foo.


回答 1

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

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

因此,仅当与某种参考点(例如os.environ['HOME']或)一起使用时,它才有意义 os.path.dirname(__file__)

The idea of os.path.join() is to make your program cross-platform (linux/windows/etc).

Even one slash ruins it.

So it only makes sense when being used with some kind of a reference point like os.environ['HOME'] or os.path.dirname(__file__).


回答 2

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

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

os.path.join() can be used in conjunction with os.path.sep to create an absolute rather than relative path.

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

回答 3

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

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

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

Do not use forward slashes at the beginning of path components, except when refering to the root directory:

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

see also: http://docs.python.org/library/os.path.html#os.path.join


回答 4

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

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

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

To help understand why this surprising behavior isn’t entirely terrible, consider an application which accepts a config file name as an argument:

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

If the application is executed with:

$ myapp foo.conf

The config file /etc/myapp.conf/foo.conf will be used.

But consider what happens if the application is called with:

$ myapp /some/path/bar.conf

Then myapp should use the config file at /some/path/bar.conf (and not /etc/myapp.conf/some/path/bar.conf or similar).

It may not be great, but I believe this is the motivation for the absolute path behaviour.


回答 5

这是因为您'/new_sandbox/'以a开头,/因此被假定为相对于根目录。拆下龙头/

It’s because your '/new_sandbox/' begins with a / and thus is assumed to be relative to the root directory. Remove the leading /.


回答 6

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

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

要么

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

To make your function more portable, use it as such:

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

or

os.path.join(os.environ.get("HOME"), 'test', 'sandboxes', todaystr, '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', '']

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

Try combo of split("/") and * for strings with existing joins.

import os

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

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


How it works…

split("/") turns existing path into list: ['', 'home', 'build', 'test', 'sandboxes', '']

* in front of the list breaks out each item of list its own parameter


回答 8

new_sandbox仅尝试

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

Try with new_sandbox only

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

回答 9

这样做,没有太多的斜线

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

do it like this, without too the extra slashes

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

回答 10

请注意,如果您使用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

Note that a similar issue can bite you if you use os.path.join() to include an extension that already includes a dot, which is what happens automatically when you use os.path.splitext(). In this example:

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

Even though extension might be .jpg you end up with a folder named “foobar” rather than a file called “foobar.jpg”. To prevent this you need to append the extension separately:

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

回答 11

你可以strip'/'

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

you can strip the '/':

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

回答 12

我建议从第二个和后面的字符串中删除字符串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)

I’d recommend to strip from the second and the following strings the string os.path.sep, preventing them to be interpreted as absolute paths:

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)

回答 13

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(os.sep))
'a/b'

a fuller version:

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