如何在Python中获取父目录?


350

有人可以告诉我如何以跨平台方式在Python中获取路径的父目录。例如

C:\Program Files ---> C:\

C:\ ---> C:\

如果该目录没有父目录,它将返回目录本身。这个问题看似简单,但我无法通过Google进行深入研究。

Answers:


480

从Python 3.4更新

使用pathlib模块。

from pathlib import Path
path = Path("/here/your/path/file.txt")
print(path.parent)

旧答案

尝试这个:

import os.path
print os.path.abspath(os.path.join(yourpath, os.pardir))

yourpath您想要父级的路径在哪里?


136
您的答案是正确的,但令人费解。os.path.dirname是此功能,例如a+=5-4a+=1。该问题仅请求父目录,而不是是否存在或假设符号链接妨碍了真正的父目录。
tzot 2010年

15
os.pardir,不是os.path.pardir
bouteillebleu'7

9
@bouteillebleu:os.pardiros.path.pardir实际上都是正确的(它们是相同的)。
Eric O Lebigot

45
@tzot:不幸的os.path.dirname是,根据路径中是否包含斜杠,会给出不同的结果。如果您想要可靠的结果,则需要使用os.path.join上面答案中的方法。
Artfunkel

21
由于这显然很复杂,足以引起StackOverflow问题,因此我认为应该将其作为内置函数添加到os.path库中。
antant

324

使用os.path.dirname

>>> os.path.dirname(r'C:\Program Files')
'C:\\'
>>> os.path.dirname('C:\\')
'C:\\'
>>>

警告:os.path.dirname()根据路径中是否包含斜杠给出不同的结果。这可能是您想要的语义,也可能不是。cf. @kender使用的答案os.path.join(yourpath, os.pardir)


6
os.path.dirname(r'C:\Program Files')什么?Python只是为您提供文件“ Program Files”所在的目录。而且,它甚至不必存在,请看:os.path.dirname(r'c:\i\like\to\eat\pie')输出'c:\\i\\like\\to\\eat'
Nick T

41
原始张贴者没有指出该目录必须存在。有很多路径名方法只对字符串进行操作。要验证路径名是否实际存在,需要进行磁盘访问。取决于应用程序,这可能是不希望的。
惠业东

10
此解决方案对尾随的os.sep敏感。说os.sep =='/'。dirname(foo / bar)-> foo,但dirname(foo / bar /)-> foo / bar
marcin 2012年

6
那是设计使然。归结为对带有尾部/的路径的解释。您是否认为“ path1”等于“ path1 /”?该库使用最一般的解释,即它们是不同的。在某些情况下,人们可能希望将它们等同。在这种情况下,您可以先执行rstrip('/')。如果图书馆选择其他解释,您将失去保真度。
惠业东

3
@Ryan,我对此一无所知。编写了完整的RFC 1808,以解决URI中的相对路径问题以及尾随/的存在和不存在的所有微妙之处。如果您知道任何说明应大致等同对待的文档,请指出。
威业东

112

Pathlib方法(Python 3.4+)

from pathlib import Path
Path('C:\Program Files').parent
# Returns a Pathlib object

传统方法

import os.path
os.path.dirname('C:\Program Files')
# Returns a string


我应该使用哪种方法?

在以下情况下,请使用传统方法:

  • 如果使用Pathlib对象,您会担心现有代码会生成错误。(由于Pathlib对象不能与字符串连接。)

  • 您的Python版本低于3.4。

  • 您需要一个字符串,并且您收到了一个字符串。假设您有一个表示文件路径的字符串,并且想要获取父目录,以便可以将其放入JSON字符串中。转换为Pathlib对象并为此再次返回是一种愚蠢的做法。

如果以上都不适用,请使用Pathlib。



什么是Pathlib?

如果您不知道Pathlib是什么,那么Pathlib模块是一个了不起的模块,它使您更轻松地处理文件。大多数(如果不是全部)与文件一起使用的内置Python模块将接受Pathlib对象和字符串。我在下面重点介绍了Pathlib文档中的几个示例,这些示例展示了您可以使用Pathlib进行的一些巧妙操作。

在目录树中导航:

>>> p = Path('/etc')
>>> q = p / 'init.d' / 'reboot'
>>> q
PosixPath('/etc/init.d/reboot')
>>> q.resolve()
PosixPath('/etc/rc.d/init.d/halt')

查询路径属性:

>>> q.exists()
True
>>> q.is_dir()
False

4
这是唯一理智的答案。如果您被迫使用Python 2,请pip install pathlib2使用backport。
纳文

1
该解决方案对拖尾不敏感os.sep
Dylan F

35
import os
p = os.path.abspath('..')

C:\Program Files -> C:\\\

C:\ -> C:\\\


7
这仅获得CWD的父级,而不是OP要求的任意路径的父级。
塞尔吉奥(Sergio)2013年

在网址末尾添加双点,它将起作用。例如, os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') 结果:E:\\O3M_Tests_Embedded\\branches
Arindam Roychowdhury 2015年

这意味着:/
loretoparisi

26

@kender的替代解决方案

import os
os.path.dirname(os.path.normpath(yourpath))

yourpath您想要父级的路径在哪里?

但是这种解决方案并不完美,因为它不能处理yourpath空字符串或点的情况。

这个其他解决方案可以更好地处理这种极端情况:

import os
os.path.normpath(os.path.join(yourpath, os.pardir))

在这里可以找到的每种情况的输出(输入路径是相对的):

os.path.dirname(os.path.normpath('a/b/'))          => 'a'
os.path.normpath(os.path.join('a/b/', os.pardir))  => 'a'

os.path.dirname(os.path.normpath('a/b'))           => 'a'
os.path.normpath(os.path.join('a/b', os.pardir))   => 'a'

os.path.dirname(os.path.normpath('a/'))            => ''
os.path.normpath(os.path.join('a/', os.pardir))    => '.'

os.path.dirname(os.path.normpath('a'))             => ''
os.path.normpath(os.path.join('a', os.pardir))     => '.'

os.path.dirname(os.path.normpath('.'))             => ''
os.path.normpath(os.path.join('.', os.pardir))     => '..'

os.path.dirname(os.path.normpath(''))              => ''
os.path.normpath(os.path.join('', os.pardir))      => '..'

os.path.dirname(os.path.normpath('..'))            => ''
os.path.normpath(os.path.join('..', os.pardir))    => '../..'

输入路径是绝对路径(Linux路径):

os.path.dirname(os.path.normpath('/a/b'))          => '/a'
os.path.normpath(os.path.join('/a/b', os.pardir))  => '/a'

os.path.dirname(os.path.normpath('/a'))            => '/'
os.path.normpath(os.path.join('/a', os.pardir))    => '/'

os.path.dirname(os.path.normpath('/'))             => '/'
os.path.normpath(os.path.join('/', os.pardir))     => '/'

标准化路径始终是一个好习惯,尤其是在进行跨平台工作时。
DevPlayer

这是正确的答案!它使相对路径保持相对。谢谢!
Maxim

@Maxim此解决方案并不完美,因为原始解决方案无法处理一种情况,所以我对其进行了改进
benjarobin

@benjarobin是的,我没有想到过这种情况。谢谢。
Maxim Maxim,

18
os.path.split(os.path.abspath(mydir))[0]

这不适用于目录路径,它将再次返回目录。
Anthony Briggs

2
@AnthonyBriggs,我刚刚在Ubuntu 12.04上使用Python 2.7.3进行了尝试,它似乎工作正常。os.path.split(os.path.abspath("this/is/a/dir/"))[0]返回'/home/daniel/this/is/a'预期。我目前没有正在运行的Windows框可供检查。在哪种设置上,您观察到了报告的行为?
Dan Menes

你可以做的parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]。我敢肯定,这是有效的,因为如果结尾处有斜杠,则将其删除;如果没有斜杠,则由于前面的斜杠,它仍然可以工作(即使路径的最后部分只有一个字符长)。当然,这是假定路径是正确的,而不是说类似的东西/a//b/c///d////(在Unix中,这仍然有效),在大多数情况下,它们是(适当的),尤其是当您执行类似的东西os.path.abspath或任何其他os.path功能时。
dylnmc 2014年

另外,要抵消最后的大量斜线,您可以编写一个小的for循环来删除那些斜线。我敢肯定,甚至有一个聪明的一线人可以做到这一点,或者可以做到这一点,然后将os.path.split一行一行。
dylnmc 2014年

@Den Menes我刚刚看到您发表评论。如果您有类似cd / dev /`或;之类的命令os.path.split("a/b//c/d///"),则此命令不起作用。所有这些都在linux中有效。我只是想出了这一点,它可能是有用的,但:。(这实际上是搜索最后一个非斜杠,并获取到该char的路径的子字符串。)我使用过,然后运行上述语句并得到了。cd //////dev////// is equivalent to cd /devos.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]path = "/a//b///c///d////"'/a//b///c'
dylnmc

14
os.path.abspath(os.path.join(somepath, '..'))

观察:

import posixpath
import ntpath

print ntpath.abspath(ntpath.join('C:\\', '..'))
print ntpath.abspath(ntpath.join('C:\\foo', '..'))
print posixpath.abspath(posixpath.join('/', '..'))
print posixpath.abspath(posixpath.join('/home', '..'))

7
import os
print"------------------------------------------------------------"
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
print("example 1: "+SITE_ROOT)
PARENT_ROOT=os.path.abspath(os.path.join(SITE_ROOT, os.pardir))
print("example 2: "+PARENT_ROOT)
GRANDPAPA_ROOT=os.path.abspath(os.path.join(PARENT_ROOT, os.pardir))
print("example 3: "+GRANDPAPA_ROOT)
print "------------------------------------------------------------"

6

如果你想名称是作为参数,并提供该文件的直接父文件夹的不是绝对路径到该文件中:

os.path.split(os.path.dirname(currentDir))[1]

即具有的currentDir/home/user/path/to/myfile/file.ext

上面的命令将返回:

myfile


3
os.path.basename(os.path.dirname(current_dir))也可以在这里使用。
DevPlayer

4
>>> import os
>>> os.path.basename(os.path.dirname(<your_path>))

例如在Ubuntu中:

>>> my_path = '/home/user/documents'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'user'

例如在Windows中:

>>> my_path = 'C:\WINDOWS\system32'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'WINDOWS'

两个示例都在Python 2.7中尝试过



3

假设我们有类似的目录结构

1]

/home/User/P/Q/R

我们要从目录R访问“ P”的路径,然后可以使用

ROOT = os.path.abspath(os.path.join("..", os.pardir));

2]

/home/User/P/Q/R

我们要从目录R访问“ Q”目录的路径,然后可以使用

ROOT = os.path.abspath(os.path.join(".", os.pardir));

2

只需在Tung的答案中添加一些内容即可(rstrip('/')如果您使用的是unix盒,则需要更加安全一些)。

>>> input = "../data/replies/"
>>> os.path.dirname(input.rstrip('/'))
'../data'
>>> input = "../data/replies"
>>> os.path.dirname(input.rstrip('/'))
'../data'

但是,如果您不使用rstrip('/'),则输入为

>>> input = "../data/replies/"

会输出

>>> os.path.dirname(input)
'../data/replies'

这可能不是您想要的,"../data/replies/"并且"../data/replies"行为方式相同。


1
我建议不要将“输入”用作变量/引用。它是一个内置功能。
DevPlayer


1
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

您可以使用它来获取py文件当前位置的父目录。


2
该建议通常会导致错误。os.getcwd()通常不在“您的py文件”所在的位置。思考包。如果我“导入some_package_with_subpackages”,则许多模块将不在该软件包的最顶层目录中。os.getcwd()返回执行最高脚本的位置。并且这也假定您是从命令行执行此操作的。
DevPlayer

0

获取父目录路径创建新目录(名称new_dir

获取父目录路径

os.path.abspath('..')
os.pardir

例子1

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.pardir, 'new_dir'))

例子2

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.path.abspath('..'), 'new_dir'))


0
import os

def parent_filedir(n):
    return parent_filedir_iter(n, os.path.dirname(__file__))

def parent_filedir_iter(n, path):
    n = int(n)
    if n <= 1:
        return path
    return parent_filedir_iter(n - 1, os.path.dirname(path))

test_dir = os.path.abspath(parent_filedir(2))

0

上面给出的答案对于上移一个或两个目录级别都是非常好的,但是如果一个人需要遍历目录树许多级别(例如5或10),它们可能会变得有些麻烦。可以通过加入中的N os.pardirs 列表来简洁地完成此操作os.path.join。例:

import os
# Create list of ".." times 5
upup = [os.pardir]*5
# Extract list as arguments of join()
go_upup = os.path.join(*upup)
# Get abspath for current file
up_dir = os.path.abspath(os.path.join(__file__, go_upup))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.