使用Python的os.path模块,我如何返回上一级目录?

322
我最近将Django从v1.3.1升级到了v1.4。
在我的旧settings.py文件中:
TEMPLATE_DIRS = (
    os.path.join(os.path.dirname( __file__ ), 'templates').replace('\\', '/'),
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

这将指向/Users/hobbes3/Sites/mysite/templates,但是Django v1.4将项目文件夹移动到与应用程序文件夹相同的级别, 所以我的settings.py文件现在位于/Users/hobbes3/Sites/mysite/mysite/而不是/Users/hobbes3/Sites/mysite/
所以,实际上我的问题现在是双重的:
  1. 我该如何使用 os.path 来查看位于 __file__ 上一级的目录。换句话说,我希望通过相对路径,在 /Users/hobbes3/Sites/mysite/mysite/settings.py 中找到 /Users/hobbes3/Sites/mysite/templates
  2. 我应该将包含跨应用程序模板(如 adminregistration 等)的 template 文件夹放在项目 /User/hobbes3/Sites/mysite 的级别还是 /User/hobbes3/Sites/mysite/mysite 的级别?

你不能只使用 os 命令来切换到 ../mysite 目录吗?或者你需要的任何其他命令。 - prelic
@prelic 嗯?我不明白。我正在尝试避免硬编码路径,因为我在多个服务器上使用相同的 settings.py 文件。唯一可能不同的是数据库凭据。我正在阅读 os.path 文档,但我找不到一个命令可以让你进入上一级目录,就像 cd .. - hobbes3
3
@hobbes3 你可以直接使用 os.path.join( os.path.dirname( __file__ ), '..' )。在整个文件系统中,.. 表示 _上一级目录_,而不仅仅是在 cd 命令中使用。 - Michael Berkowski
3
@Michael,最好使用os.path.join(os.path.dirname(__file__), os.path.pardir) - mgilson
17个回答

394
os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'templates'))

关于模板文件夹应该放在哪里,我不确定因为Django 1.4刚刚发布,我还没有看过。你应该在SE上提问解决这个问题。

你也可以使用normpath来清理路径,而不是abspath。然而,在这种情况下,Django期望的是绝对路径而不是相对路径。

为了实现跨平台兼容性,请使用os.pardir代替'..'


6
使用 .. 或其他类似的东西是个不好的主意吗?为什么这个答案得票越来越少了? - hobbes3
2
我不知道为什么它得到的投票变少了,但这是我一直在使用的。甚至在normpath的示例中也有定义。此外,它可以正确遍历符号链接。 - forivall
2
刚刚有人提出了一个关于迁移Django新版本文件夹结构的问题,你可以参考这个链接来解决你的第二个问题。 - forivall
3
使用 abspath 只是稍微清理了一下路径。如果不使用它,路径名的实际字符串将为/Users/hobbes3/Sites/mysite/mysite/../templates,这也完全没问题,只是有点混乱。它还确保 Django 的绝对路径提示被遵守。如果你处于另一种使用相对路径的情况下,应该使用 normpath 来简化路径。 - forivall
1
@Zitrax 你知道有哪些平台会有所不同吗?还是这只是为了未来的安全考虑?(我实际上并不知道 os.pardir,从未深入研究过 os 文档) - forivall
显示剩余6条评论

152

要获取文件所在的文件夹,只需使用以下代码:

os.path.dirname(path) 

只需再次使用os.path.dirname即可返回上级文件夹。

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

你可能想要检查 __file__ 是否是一个符号链接:

if os.path.islink(__file__): path = os.readlink (__file__)

20
有没有一种方法可以在不调用 os.path.dirname n 次的情况下向上跳转 n 层文件夹? - Oriol Nieto
17
是的,在 Python 3.4 及以上版本中,你可以使用 pathlib.Path.parents[levels_up-1]。更多解决方案请参考 这个问题 - jwalton

94

如果您使用Python 3.4或更新版本,则可使用pathlib方便地向上移动多个目录:

from pathlib import Path

full_path = "path/to/directory"
str(Path(full_path).parents[0])  # "path/to"
str(Path(full_path).parents[1])  # "path"
str(Path(full_path).parents[2])  # "."

10
这绝对是最干净的方法。 - hobbes3

25
你需要的是这个:
BASE_DIR = os.path.join( os.path.dirname( __file__ ), '..' )

13

个人而言,我会选择函数方法

def get_parent_dir(directory):
    import os
    return os.path.dirname(directory)

current_dirs_parent = get_parent_dir(os.getcwd())

1
请注意,如果输入包含尾随斜杠(例如os.path.dirname('/tmp/lala/')),此答案将无法工作,仍将返回'/tmp/lala' - 林果皞
尾部斜杠的情况可以参考此答案:https://dev59.com/onE85IYBdhLWcg3wRBRU#25669963 - 林果皞

12

如果您希望用一行代码获取上级目录,我建议使用以下代码:

import os
    
parent_dir = os.path.split(os.getcwd())[0]

os.path.split() 方法返回一个元组 (head, tail),其中 tail 是最后一个斜杠之后的所有内容。因此,第一个索引是您绝对路径的父目录。


9
我认为最简单的方法就是重复使用dirname(),这样你就可以调用它。
os.path.dirname(os.path.dirname( __file__ ))

如果您的文件位于 /Users/hobbes3/Sites/mysite/templates/method.py,
那么这将返回 "/Users/hobbes3/Sites/mysite"。

7

这可能对其他需要向上跳转x个文件夹的情况有用。只需运行walk_up_folder(path, 6)即可向上跳转6个文件夹。

def walk_up_folder(path, depth=1):
    _cur_depth = 1        
    while _cur_depth < depth:
        path = os.path.dirname(path)
        _cur_depth += 1
    return path   

可以只使用 for _ in xrange(depth) 而不是跟踪局部变量。 - Zitrax

7
from os.path import dirname, realpath, join
join(dirname(realpath(dirname(__file__))), 'templates')

更新:

如果您通过符号链接“复制”settings.py文件,@forivall的答案更好:

~user/
    project1/  
        mysite/
            settings.py
        templates/
            wrong.html

    project2/
        mysite/
            settings.py -> ~user/project1/settings.py
        templates/
            right.html

上述方法将“看到”wrong.html,而@forivall的方法将看到right.html 在没有符号链接的情况下,这两个答案是相同的。

这种方法有什么问题吗?它的工作效果很好,看起来也不错,但有点像hack。 ;) - Gricha
它在处理链接方面与被接受的答案略有不同,但其他方面都是相同的。 - Antony Hatchkins

5

返回到工作目录的上一层级

import os
os.path.dirname(os.getcwd())

或从当前目录

import os
os.path.dirname('current path')

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