如何在Python脚本中获取资源文件的完整路径?

3

好的,我编写了一个放在包中的Python脚本。目录树看起来大致是这样的:

├── foo
│   ├── __init__.py
│   ├── funcs
│   │   ├── __init__.py
│   │   └── stuff.py
│   ├── resources
│   │   └── haarcascade_frontalface_default.xml
│   └── scripts
│       ├── __init__.py
│       └── script.py
└── setup.py

在脚本文件中,我使用openCV的cv2来检测人脸,为此,cv2.CascadeClassifier需要XML文件的路径,该文件位于/resources下。由于这是一个脚本,我需要能够从任何地方运行它,因此相对路径到资源文件不能正常工作。如何在script.py内获取xml文件的绝对路径?您可以假设脚本和xml文件彼此相关,就像上面的示例一样。谢谢:)
附带说明:如果此解决方案也适用于eggs,则会有奖励。非常感谢。
3个回答

6

目前最好的做法是使用 importlib.resources。自 Python 3.7 起,它已经可以在标准库中使用。对于早期版本,有一个称为 importlib_resources 的后移版。

请参阅文档

在您的情况下,这应该大致如下:

import importlib.resources
xml_path = importlib.resources.path('foo.resources', 'haarcascade_frontalface_default.xml')

这样做有很多好处,最重要的是它是标准的,在任何安装了该包的地方都能工作,即使它在一个压缩文件中。

在您的情况下,您可能需要资源目录中添加一个__init__.py文件。


2

使用 os 模块可以解决问题,但如果您拥有 Python 版本 >= 3.4,则 pathlib 是一个替代方案,它更易于处理并在各个平台上表现更好:

from pathlib import Path

# when using pathlib.Path, slashes get automatically transformed into the 
# correct path-division character, depending on the platform
RESOURCES_PATH = Path(__file__).parent.parent / "resources"

face_cascade = cv2.CascadeClassifier()
face_cascade.load(RESOURCES_PATH / "haarcascade_frontalface_default.xml")

如果你发现自己定义了很多这样的常量,考虑将它们全部放在一个文件(例如foo/util.py)中,以便在项目中轻松地重复使用,而不需要从脚本中重新声明或导入。
在Python版本>=3.7中,更好的选择是使用importlib.resources.path,它会自动从包根目录解析资源,因此你无需手动查找,也不需要从__file__向上遍历。
import importlib

face_cascade = cv2.CascadeClassifier()
with importlib.resources.path("foo.resources", "haarcascade_frontalface_default.xml") as haar_resource:
    # haar_resource is a pathlib.Path object here as well, so plugging it is simple
    face_cascade.load(haar_resource)

这种方法更加优雅,如果可用的话,应该是首选解决方案。

1
请使用标准库importlib.resources或其后备库importlib_resources - sinoroc
1
不知道这个,谢谢。它看起来比替代方案要好很多。 - Arne

-3

我不确定我是否正确理解了问题,但也许os.path可以帮助你?类似这样:

>>> import os
>>> os.path.abspath("directory/somefile.txt")
'C:/somedirectory/directory/directory/somefile.txt'

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