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

Why doesn't os.path.join() work in this case?

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

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

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


后一个字符串不应以斜线开头。如果它们以斜线开始,那么它们被认为是"绝对路径",在它们被丢弃之前的一切都被丢弃。

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

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

注意:在Windows中,与驱动器号相关的行为,与早期的python版本相比似乎有所改变:

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.


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

即使是一个斜线也会毁了它。

因此,只有在与类似的参考点一起使用时才有意义os.environ['HOME']os.path.dirname(__file__)


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

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


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

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

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


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

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

如果应用程序是用以下方式执行的:

1
$ myapp foo.conf

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

但是考虑一下如果用以下方法调用应用程序会发生什么:

1
$ myapp /some/path/bar.conf

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

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


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


要使您的功能更易于移植,请按如下方式使用:

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

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

对于具有现有联接的字符串,尝试使用split("/")*的组合。

1
2
3
4
5
6
7
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', '']

列表前的*将列表中的每一项都分解为自己的参数。


仅使用new_sandbox尝试

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

像这样做,不要太多的斜杠

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

请注意,如果您使用os.path.join()来包含已经包含点的扩展,则类似的问题可能会咬到您,这是使用os.path.splitext()时自动发生的情况。在本例中:

1
2
3
4
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"的文件。要防止出现这种情况,需要单独附加扩展名:

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