如何创建一个“始终相对于当前模块”的文件路径?

102

假设你有一个包含以下内容的模块:

myfile = open('test.txt', 'r')

如果你运行这个模块,'test.txt'文件在同一个文件夹中将会成功打开。

现在假设你从另一个在不同文件夹中的模块中导入该模块,文件将不会在与包含该代码的模块相同的文件夹中搜索。

那么如何使该模块首先使用相对路径在同一文件夹中搜索文件呢?

有多种解决方案可以使用"__file__"或"os.getcwd()",但我希望有一种更简洁的方法,比如在传递给open()或file()的字符串中使用相同的特殊字符。


os.getcwd()有什么问题? - cfedermann
3
os.getcwd() 返回第一个导入该模块或导入另一个已导入它的模块的模块的路径。第一个模块可能位于许多上下级目录中,所以键入 os.getcwd()+'something/somethingelse/yetanother/finallyhere' 看起来不太优美。 - user975135
不;os.getcwd()返回的是进程的当前工作目录,这与任何模块都没有必然的关联。 - undefined
2个回答

126

解决方案是使用__file__,这非常简洁:

import os

TEST_FILENAME = os.path.join(os.path.dirname(__file__), 'test.txt')

1
当你使用import os时,模块会自动导入os.pathos是特殊的)。因此,import os.path是没有意义的。虽然可以使用from os import path,但在os模块的情况下并不常见。很可能他已经在模块中使用了import os或者很快就需要使用它。因此,import os几乎总是最好的选择。 - yak
我想这已经是最干净的了。再多要求就需要改变官方Python解释器的工作方式了。 - user975135
os 已经导入了 os.path 这一事实是一个实现细节。虽然约定已经被确立并且不太可能改变,但你不应该依赖于实现细节。当使用 os.path 时,明确地导入 os.path 是永远不会无意义的。 - Martijn Pieters
首先要添加 os.path.realpath() 以获取绝对路径。 - Martijn Pieters

54

对于从.py文件加载的普通模块,应该存在并可以使用__file__。如果要将__file__中的信息与相对路径连接起来,有一种比2014年以来提供的os.path接口更新的选项:

from pathlib import Path

here = Path(__file__).parent
fname = here / "test.txt"
with fname.open() as f:
    ...

pathlib是在Python 3.4中添加的 - 请参见PEP428。 对于仍在使用Python 2.7并希望使用相同API的用户,可使用后移植版本

请注意,在处理Python包时,有更好的方法可用于读取资源 - 您可以考虑迁移到importlib-resources。这需要Python 3.7+,对于旧版本,您可以使用pkgutil。正确打包资源的一个优点是,与相对于源树连接数据文件不同,代码仍将在未从文件系统提取(例如在zipfile中的包中)的情况下工作。有关在包中读取/写入数据文件的更多详细信息,请参见如何从Python程序包内部读取(静态)文件?


Path(来自pathlib)提供了许多方便的跨平台功能,与os相比,这将是总体上最整洁的方法。 - Marc Maxmeister
由于使用了pathlib,这是我的首选解决方案。 - Akash Desarda

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