Python:如何获取文件路径的最后n个元素

6

假设我有这样一个路径:

/folderA/folderB/folderC/item1
/folderA/folderB/folderX/item2
/folderA/folderB/folderF/item1
/folderA/folderB/folderQ/item5

如何获取文件路径的最后两个元素?

folderC/item1
folderX/item2
folderF/item1
folderQ/item5

我知道我可以通过以下方式获取文件夹或文件:


```git ```
>>> os.path.basename('/folderA/folderB/folderC/item1')
>>> item1


>>> os.path.dirname('/folderA/folderB/folderC/item1')
>>> /folderA/folderB/folderC/
3个回答

10
from pathlib import Path
path = r"/folderA/folderB/folderC/item1"
Path(*Path(path).parts[-2:])

输出:

PosixPath('folderC/item1')

注意:如果您愿意,可以将PosixPath对象转换为字符串。


9
import os
path = r"/folderA/folderB/folderC/item1"

For Windows:

os.sep.join(path.rsplit(r"/")[-2:])

跨平台:

os.sep.join(os.path.normpath(path).split(os.sep)[-2:])

1
你可能希望以一种与操作系统无关的方式来完成这个任务。在这种情况下,您应该使用os.path例程来实现。然而,os.path.split()与普通的split()不同,因此您不能直接将其用于所需的操作。
您可以使用splitall(path)方法这里。我不会包含代码,因为我没有编写它,所以我只会链接到它。 splitall()重复使用os.path.split()来拆分路径。
它返回一个包含路径组件的列表。然后,您可以通过对返回的列表执行切片操作来选择最后三个组件。如果您想要将最后三个组件再次合并为路径,则应使用os.path.join()

我在Stack Overflow上找到了一个版本这里,我更喜欢它。我已经链接到答案,但由于它在该网站上(因此受CC BY-SA保护),我将更充分地展开并在此处包含代码。警告,我只在Windows上测试过,但应适用于其他操作系统。如果不行,请告诉我。

import os
def split_path(path):
    folders = []
    drive, path = os.path.splitdrive(path)
    while True:
        path, folder = os.path.split(path)

        if folder:
            folders.append(folder)
        else:
            if path:
                folders.append(path)
            break
        
    if drive:
        folders.append(drive)
    return folders[::-1]

我在测试@Andreas的答案时,仅使用os.path.normpath(path).split(os.sep)[-2:]而不是os.sep.join(),因为我将其用于生成文件夹列表,代替上面的splitall()/split_path()以获取所有路径组件的列表。从我的角度来看,这是一个更加常用的工具,尽管我承认它对于OP的问题并非必需。
在这种情况下,split(os.sep)做错了事情。它使用前导分隔符作为分隔符(显然),因此返回一个空路径元素,而不是前导根目录(即分隔符)。当您想要一个目录组件列表时,这是错误的。当您包括join时,这不明显,因为当您将前导空条目与其余条目连接起来时,它会将其与分隔符一起连接到前面。因此,在一般的非连接情况下,我认为这是有问题的。
为了完整起见,下面的reconstruct_path()将从文件夹列表重建路径。它将处理Windows上的驱动器,包括包含驱动器的相对路径,这可能是一件事。
import os
import sys

def reconstruct_path(folders):
    folders = folders[:]
    path = ""

    # On windows, pop off the drive if there is one. Affects handling of relative vs rooted paths 
    if sys.platform == 'win32' and ':' == folders[0][-1]:
        path = folders[0]
        del folders[0]
    if folders and folders[0] == os.sep:
        path += folders[0]
        del folders[0]
    path += os.sep.join(folders)
    return path

我的意思是,如果你想要操作系统无关性,你也可以这样做:os.sep.join(os.path.normpath(path).split(os.sep)[-2:]) 但在我看来,可读性极差。 - Andreas
@Andreas 如果路径是绝对路径(带有前导'/'或'\',具体取决于您的操作系统),那么这个一行代码就不起作用。它在列表中给出了一个“。”,而根应该在那里。我知道在OP的情况下,这不是问题,因为OP忽略了前面的内容,只查看最后两个路径元素。但是,如果有人寻找通用解决方案时遇到此问题,我想警告他们这个一行代码可能会有问题。 - Glenn Mackintosh
感谢您的评论,您确定是这种情况吗?我发布了第二个与操作系统无关的行。我测试了带有“/”和“\”的前导符号:path = r"/folderA\folderB/folderC\item1",对我来说完全正常,因为normpath会将其清除。 - Andreas
@Andreas 很有趣。我在没有使用join的情况下进行了测试,因为我使用的是splitall()而不是上面的方法,它返回所有路径组件的列表。在这种情况下,它会出现错误,因为它使用前导分隔符作为分隔符(显然),所以它返回一个空路径元素,而不是前导根目录(即分隔符)。当您想要一个目录组件列表时,这是错误的。join()隐藏了这一点,因为当您将前导空条目与其余部分连接起来时,它会使用分隔符将其添加到前面。在一般非join()情况下仍然存在问题。 - Glenn Mackintosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接