如何获取父目录位置

171

这段代码是在b.py中获取templates/blog1/page.html模板:

path = os.path.join(os.path.dirname(__file__), os.path.join('templates', 'blog1/page.html'))

但我想获取父目录的位置:

aParent
   |--a
   |  |---b.py
   |      |---templates
   |              |--------blog1
   |                         |-------page.html
   |--templates
          |--------blog1
                     |-------page.html

如何获取aParent的位置?

谢谢。

更新:

这是正确的:

dirname=os.path.dirname
path = os.path.join(dirname(dirname(__file__)), os.path.join('templates', 'blog1/page.html'))
或者
path = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))

2
你想获取 blog1 还是 a?而且你当前的文件在哪里? - Felix Kling
你明白你的代码在做什么吗? - SilentGhost
2
是的,它获取 templates/blog1/page.html。 - zjm1126
os.path.join('templates', 'blog1/page.html')对我来说听起来很奇怪。你混淆了一些事情。要么是os.path.join('templates', 'blog1', 'page.html'),要么是'templates/blog1/page.html'。而更简单的方法是使用os.path.abspath(os.path.join('templates', 'blog1', 'page.html')) - Felix Kling
1
@zjm:不,你不能获取那个页面。它不是一个黑匣子,你不能只是用它来获取模板文件。它执行一系列微不足道的小步骤,如果你能理解它们,你就不会有这个问题了。 - SilentGhost
那么如何获取页面和'a'目录的位置呢? - zjm1126
12个回答

224
你可以反复使用dirname来向上爬升:dirname(dirname(file))。但是这只能到达根目录包的层级。如果这是一个问题,可以使用os.path.abspathdirname(dirname(abspath(file)))

43
我知道OP知道dirname的用法。但并不是所有人都明白将dirname应用于目录会产生其父目录这一点。 - Marcelo Cantos
6
dirname 不总是返回父目录;http://twitter.com/#!/ActiveState/status/671049326788608 - Sridhar Ratnakumar
2
@Sridhar:这取决于你的观点;我认为以 / 结尾的路径不代表叶目录本身,而是它的内容,这就是为什么例如 mv xxx yyy/ 如果 yyy 不是一个已存在的目录,则会失败。无论如何,即使我们将您的观点视为给定的,在我的答案背景下也是无关紧要的。无论是 file 还是 dirname 的结果都不会以 / 结尾。 - Marcelo Cantos
1
小修正:dirname 可能会返回 '/',它明显以 / 结尾。这是我所知道的唯一例外。 - Marcelo Cantos

77

在Python 3.4+中,使用pathlib模块的相对路径(relative path)

from pathlib import Path

Path(__file__).parent

您可以多次使用parent来进一步定位路径:

Path(__file__).parent.parent

作为指定 parent 两次的替代方案,您可以使用:

Path(__file__).parents[1]

2
如果您需要将路径作为字符串使用以进行修改,您可以使用str(Path(__file__).parent) - Philipp
3
在Python 3.8.5中,似乎需要使用Path(__file__).resolve().parent - Markus Kaukonen
2
谢谢,我知道 .parent 但不知道 .parents。在我看来,这比链接 .parentos.path.dirname 更好。 - hkennyv

68

os.path.abspath 不会验证任何内容,所以如果我们已经将字符串附加到 __file__ 上,就不需要麻烦使用 dirname 或连接等操作。只需将 __file__ 视为目录并开始上升即可:

# climb to __file__'s parent's parent:
os.path.abspath(__file__ + "/../../")

这要比 os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) 更清晰简洁,而且与 dirname(dirname(__file__)) 差不多易于管理。如果超过两个级别,那就开始变得荒谬。

但是,由于我们知道要爬升多少级,我们可以用一个简单的小函数来使代码更简洁:

uppath = lambda _path, n: os.sep.join(_path.split(os.sep)[:-n])

# __file__ = "/aParent/templates/blog1/page.html"
>>> uppath(__file__, 1)
'/aParent/templates/blog1'
>>> uppath(__file__, 2)
'/aParent/templates'
>>> uppath(__file__, 3)
'/aParent'

3
这很不错,但如果标准库能添加一个方便的函数来完成这个操作就更好了...我不想每次需要这个函数时都要来Stack Overflow。 - gradi3nt
6
os.path.abspath(os.path.join(__file__, "..", "..")) 是否更具可移植性? - slowD

14
os.path.dirname(os.path.abspath(__file__))

应该会给你 a 的路径。

但是如果当前执行的文件是 b.py,那么你可以通过以下方式实现相同的效果:

os.path.abspath(os.path.join('templates', 'blog1', 'page.html'))

1
哦,我知道你是对的,我想要获取a文件夹的父级文件夹。如何获取它? - zjm1126
@zjm1126:请参考Marcelo Cantos的回答。使用dirname()两次。现在您需要的一切都应该在这个网站上了。 - Felix Kling

9

os.pardir是比../更好且更易读的方式。

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

这将返回给定路径的父级路径。

6
一种简单的方法是:
import os
current_dir =  os.path.abspath(os.path.dirname(__file__))
parent_dir = os.path.abspath(current_dir + "/../")
print parent_dir

3
也许可以将两个..文件夹组合起来,以获取父文件夹的父文件夹?
path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),"..",".."))

2
使用以下内容以跳转到上一个文件夹:
os.chdir(os.pardir)

如果您需要多次跳转,则一个好而简单的解决方案是在这种情况下使用一个简单的装饰器。


2

这里有另一个相对简单的解决方案:

  • 不使用dirname()(在像"file.txt"这样的一级参数或相对父文件夹如“..”中无法按预期工作)
  • 不使用abspath()(避免任何关于当前工作目录的假设),而是保留路径的相对特性

只需使用normpathjoin

def parent(p):
    return os.path.normpath(os.path.join(p, os.path.pardir))

# Example:
for p in ['foo', 'foo/bar/baz', 'with/trailing/slash/', 
        'dir/file.txt', '../up/', '/abs/path']:
    print parent(p)

结果:

.
foo/bar
with/trailing
dir
..
/abs

1


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

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