如何仅获取父目录的名称,而不是完整路径?

4

我正在尝试仅获取父目录的名称。也就是说,只需要最后一个组成部分,而不是完整路径。

例如对于路径a/b/c/d/e,我想要获取d,而不是a/b/c/d

我的当前代码:

import os

path = "C:/example/folder/file1.jpg"
directoryName = os.path.dirname(os.path.normpath(path)) 
print(directoryName)

这将打印出 C:/example/folder,我想只获取 folder

只使用 split - SuperStew
@smci:我没有说这是重复的。在我看来,一些答案可以修改以解决这个问题。 - VPfB
1
@VPfB:这绝对是重复的问题,已经有很多类似的问题存在了。我们只需要找到一个好的重复目标然后关闭它。(我查看了一下,发现有很多质量不高的重复问题)。 - smci
2
为什么不使用“path”?“pathlib”呢?它也被禁止了吗?它必须是操作系统无关的吗?那相对路径呢,比如“a/b/../c”? - MisterMiyagi
1
“不带完整路径”是什么意思?“完整路径”对任务有什么影响? - AMC
显示剩余5条评论
5个回答

11

最简单的方法是使用pathlib。使用parent将获取父级的完整路径,name将只给出最后一个组件:

>>> from pathlib import Path
>>> path = Path("/a/b/c/d/e")
>>> path.parent.name
'd'

相比之下,要使用os.path完成同样的操作,您需要获取路径的basename所在目录的dirname。因此,翻译为:

import os

path = "C:/example/folder/file1.jpg"
print(os.path.basename(os.path.dirname(path)))

哪个是更好的版本:

os.path.split(os.path.split(path)[0])[1]

当两者都给出:

'folder'

如您所见,pathlib 的方法更加清晰易读。由于 pathlib 采用了面向对象的方式来表示路径,而不是字符串,因此我们可以清晰地观察到属性和方法的链条。{{}}
path.parent.name

按顺序阅读:

从路径开始 -> 取其父级 -> 取其名称

而在使用字符串方式的 os 函数中,实际上需要从内向外阅读!

os.path.basename(os.path.dirname(path))

按顺序阅读为:

路径的父级名称

相信您会同意,这样更难阅读和理解(这只是一个简单的例子)。


你也可以使用str.split方法和os.sep一起使用:

>>> path = "C:\\example\\folder\\file1.jpg"
>>> path.split(os.sep)[-2]
'folder'

但是正如文档所述:

请注意,仅仅知道这个分隔符是不足以解析或连接路径名的 - 使用os.path.split()os.path.join() - 但有时它很有用。


1
os.path 不再是现在的正确方法。pathlib.Path 是现在应该使用的方法。是的,这是一个负面评价,因为这是错误的、容易出错的建议。 - FHTMitchell
我喜欢进步和学习,并感谢关于pathlib的建议,但想知道使用os有什么问题。@FHTMitchell - Tomerikoo
2
@Tomerikoo 这个链接可能是一个不错的起点。 - AMC
最终之所以会这样,是因为你使用字符串来表示路径,而路径本身有很多无法表达的状态。你不得不堆积这些长而模糊的函数,它们在不同的操作系统上运行方式也不同。相信我,使用路径对象而不是字符串会更好很多。 - FHTMitchell

5
使用 pathlib.Path 获取 .name.parent
from pathlib import Path

p = Path("C:/example/folder/file1.jpg")
print(p.parent.name)  # folder

os.path 相比,pathlib 将路径表示为单独的类型而不是字符串。它通常更短、更方便使用。

2
如果您解释为什么现在更喜欢使用pathlib模块而不是旧的os.path,那会很有帮助。 - smci
1
@smci 在这个主题上似乎有很多在线资源可供使用,仅仅分享一个链接并不好,但他们可以从像https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/这样的文章中获取一些要点。 - AMC
@MisterMiyagi 哦,是的,我只是在考虑像 abc.jpg 这样的文件扩展名。 - AMC
1
@smci 我们应该在一句简洁的话或段落中总结链接的主要观点,以便Stack Overflow的读者可以了解主要观点,同时也让搜索引擎能够收录。抱歉如果我的评论不太清楚,我试图传达的就是这个意思!我甚至没有想到答案应该链接到文章上。 - AMC
@AMC:啊,我们基本上是同意的。最好的做法是同时在这里总结主要观点并引用链接(既要给予应有的归属,避免任何剽窃的出现,也要为作者提供链接爱,还要向OP证明这些建议是有权威共识的。并使“最佳”答案更客观。) - smci
显示剩余3条评论

0

这个有效

path = "C:/example/folder/file1.jpg"
directoryName = os.path.dirname(path) 
parent = directoryName.split("/")
parent.reverse()
print(parent[0])



不再使用os,改用pathlib,它可以做任何os所能做的事情,而且更容易使用。 - questionto42

0

使用pathlib轻松解决

0. 从pathlib导入Path

from pathlib import Path
path = "C:/example/folder/file1.jpg"

1. 获取一级父级

parent_lv1 = Path(path).parent

2. 获取父级别 2

parent_lv2 = parent_lv1.parent

3. 获取父元素

imm_parent = parent_lv1.relative_to(parent_lv2)
print(imm_parent)

使用pathlib很容易解决。是的,只需按照MisterMiyagi在他们的答案中建议的方式操作即可。这种解决方案已经被kederrac在这里提到过了。 - AMC
@AMC 这个答案并不像被接受的答案那样简单。但是,它很有创意,使用了relative_to的想法,这对于这个问题来说可能太复杂了,但在其他问题上可能会有所帮助。即使这个解决方案之前已经被kederrac提到过,但是那篇文章和用户已经消失了。由于这个解决方案并不简单,因此没有点赞。标题完全错误。 - questionto42

-1

我更喜欢正则表达式

import re

def get_parent(path: str) -> str:
    match = re.search(r".*[\\|/](\w+)[\\|/].*", path)
    if match:
        return match.group(1)
    else:
        return ""



if __name__ == '__main__':
    my_path = "/home/tony/some/cool/path"
    print(get_parent(my_path))
    win_path = r"C:\windows\path\has\dumb\backslashes"
    print(get_parent(win_path))

输出

cool
dumb

3
我更喜欢正则表达式。为什么? - AMC
3
为什么有人会更喜欢使用正则表达式来实现这个功能呢?这种方法在所有客观方面都比path.split(os.sep)[-2](或其他方法)更糟糕。不够清晰,代码行数多余,不够具备未来性,更加脆弱。 - smci
我理解你的观点,我的解决方案更加脆弱且不够清晰。对于字符串处理(这就是路径所涉及的所有内容),我自然而然地更喜欢正则表达式。同一个问题有很多解决方案。对于那些没有记住不断变化的stdlib的人来说,我选择了这种方法。抱歉我没有更符合“Pythonic”的风格。 - marketzero
对于marketzero来说,SO并不是在你发表答案时提供最快或最简单的方法。你也可以提供一个过于复杂的解决方案,只要它能够工作。它可能仍然对其他问题有所帮助。例如,我会使用正则表达式来查找文件中的所有路径,并将它们替换为它们的父级名称。编辑建议:我会将"I prefer regex"改为"This is is overcomplicating things, just for completeness:"。 - questionto42

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