如何从 python 脚本中获取资源文件的完整路径?
How to get full path of resource file from within python script?
好的,所以我在包中制作了一个 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
需要位于 /resources 下的 XML 文件的路径。现在因为这是一个脚本,我需要能够从任何地方 运行 它,所以很遗憾,资源文件的相对路径并不能解决问题。如何从 script.py 中获取 xml 文件的绝对路径?您可以假设脚本和 xml 文件分别相对于彼此定位,就像上面的示例一样。谢谢:))
PS:如果解决方案也适用于鸡蛋,则奖励。非常感谢
我不确定我是否正确理解了问题,但也许 os.path
会有所帮助?类似于:
>>> import os
>>> os.path.abspath("directory/somefile.txt")
'C:/somedirectory/directory/directory/somefile.txt'
使用 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)
这更优雅,应该是首选解决方案,因为它可用。
目前最好的方法是 importlib.resources
. Since Python 3.7 it is available in the standard library. For earlier versions, there is a backport called importlib_resources
。
在您的情况下,这应该大致如下所示:
import importlib.resources
xml_path = importlib.resources.path('foo.resources', 'haarcascade_frontalface_default.xml')
这有很多优点,最重要的是它是标准的,即使安装在 zip 文件中,它也可以在安装包的任何地方使用。
在您的情况下,您可能 必须将 __init__.py
文件添加到 resources
目录。
好的,所以我在包中制作了一个 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
需要位于 /resources 下的 XML 文件的路径。现在因为这是一个脚本,我需要能够从任何地方 运行 它,所以很遗憾,资源文件的相对路径并不能解决问题。如何从 script.py 中获取 xml 文件的绝对路径?您可以假设脚本和 xml 文件分别相对于彼此定位,就像上面的示例一样。谢谢:))
PS:如果解决方案也适用于鸡蛋,则奖励。非常感谢
我不确定我是否正确理解了问题,但也许 os.path
会有所帮助?类似于:
>>> import os
>>> os.path.abspath("directory/somefile.txt")
'C:/somedirectory/directory/directory/somefile.txt'
使用 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)
这更优雅,应该是首选解决方案,因为它可用。
目前最好的方法是 importlib.resources
. Since Python 3.7 it is available in the standard library. For earlier versions, there is a backport called importlib_resources
。
在您的情况下,这应该大致如下所示:
import importlib.resources
xml_path = importlib.resources.path('foo.resources', 'haarcascade_frontalface_default.xml')
这有很多优点,最重要的是它是标准的,即使安装在 zip 文件中,它也可以在安装包的任何地方使用。
在您的情况下,您可能 必须将 __init__.py
文件添加到 resources
目录。