使用代码存储库时如何引用资源的相对路径
- 2025-02-27 09:06:00
- admin 原创
- 76
问题描述:
我们正在使用一个代码存储库,该存储库部署到 Windows 和 Linux - 有时位于不同的目录中。项目内的模块之一应如何引用项目中的非 Python 资源之一(CSV 文件等)?
如果我们做类似的事情:
thefile = open('test.csv')
或者:
thefile = open('../somedirectory/test.csv')
仅当脚本从一个特定目录或目录的子集运行时它才会起作用。
我想做的是这样的:
path = getBasePathOfProject() + '/somedirectory/test.csv'
thefile = open(path)
是否可以?
解决方案 1:
尝试使用相对于当前文件路径的文件名。例如“./my_file”:
fn = os.path.join(os.path.dirname(__file__), 'my_file')
在 Python 3.4+ 中,您还可以使用pathlib:
fn = pathlib.Path(__file__).parent / 'my_file'
解决方案 2:
如果您正在使用安装工具或分发(setup.py 安装),那么访问这些打包资源的“正确”方法似乎是使用 package_resources。
在你的情况下,示例如下
import pkg_resources
my_data = pkg_resources.resource_string(__name__, "foo.dat")
当然,它会读取资源,读取的二进制数据将是 my_data 的值
如果你只需要文件名,你也可以使用
resource_filename(package_or_requirement, resource_name)
例子:
resource_filename("MyPackage","foo.dat")
其优点是,即使是像 egg 这样的档案发行版也能保证正常工作。
请参阅http://packages.python.org/distribute/pkg_resources.html#resourcemanager-api
解决方案 3:
在 Python 中,路径是相对于当前工作目录的,在大多数情况下,当前工作目录是您运行程序的目录。当前工作目录很可能与模块文件的目录不同,因此使用相对于当前模块文件的路径始终是一个糟糕的选择。
使用绝对路径应该是最好的解决方案:
import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')
解决方案 4:
我经常使用类似这样的东西:
import os
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'datadir'))
# if you have more paths to set, you might want to shorten this as
here = lambda x: os.path.abspath(os.path.join(os.path.dirname(__file__), x))
DATA_DIR = here('datadir')
pathjoin = os.path.join
# ...
# later in script
for fn in os.listdir(DATA_DIR):
f = open(pathjoin(DATA_DIR, fn))
# ...
变量
__file__
保存您编写该代码的脚本的文件名,因此您可以创建相对于脚本的路径,但仍使用绝对路径编写。它工作得很好,原因如下:
路径是绝对的,但仍然是相对的
项目仍然可以部署在相关容器中
但是您需要注意平台兼容性 - Windows 的 os.pathsep 与 UNIX 不同。
解决方案 5:
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)
您还尝试规范化您的cwd
使用os.path.abspath(os.getcwd())
。更多信息请点击此处。
解决方案 6:
您可以使用内置变量__file__
。它包含当前文件的路径。我将在项目根目录中的模块中实现 getBaseOfProject。在那里我将获取路径部分__file__
并返回它。然后可以在项目中的任何地方使用此方法。
解决方案 7:
我在这里有点困惑。想将一些资源文件打包成一个 wheel 文件并访问它们。使用清单文件进行了打包,但 pip install 不会安装它,除非它是一个子目录。希望这些屏幕截图能有所帮助
├── cnn_client
│ ├── image_preprocessor.py
│ ├── __init__.py
│ ├── resources
│ │ ├── mscoco_complete_label_map.pbtxt
│ │ ├── retinanet_complete_label_map.pbtxt
│ │ └── retinanet_label_map.py
│ ├── tf_client.py
清单
recursive-include cnn_client/resources *
使用标准 setup.py 创建了一个 wheel。pip 安装了 wheel 文件。安装后检查资源是否已安装。它们是
ls /usr/local/lib/python2.7/dist-packages/cnn_client/resources
mscoco_complete_label_map.pbtxt
retinanet_complete_label_map.pbtxt
retinanet_label_map.py
在 tfclient.py 中访问这些文件。来自
templates_dir = os.path.join(os.path.dirname(__file__), 'resources')
file_path = os.path.join(templates_dir, \n 'mscoco_complete_label_map.pbtxt')
s = open(file_path, 'r').read()
并且它有效。
解决方案 8:
既然你说你有一些代码要部署到各个地方,那么你应该使用 python 生态系统来分发资源,而不仅限于文件。它还支持访问 zip 档案中的文件,这很好,这样你就不必为此烦恼了。
以前,这个问题是用pkg_resources
from处理的setuptools
,但随着越来越多的工具出现,生态系统发生了变化。从 python 3.7 开始,你应该使用importlib.resources
import importlib.resources
with importlib.resources.open_text('mypackage.somedirectory','text.csv') as f:
print(f.read()) # or whatever
但您还必须指示安装程序包含包资源。否则,pip install mypackage
将不会捆绑数据文件。
有很多方法可以做到这一点,但其中一种方法是添加
[options.package_data]
mypackage =
"somedirectory/*.csv"
放入你的。在使用或时,setup.cfg
有等效的方法。setuptools主页上提供了更完整的说明setup.py
`pyproject.toml`
解决方案 9:
如果您希望稍后将脚本编译为 .exe,则__file__
不会为您提供 .exe 文件的路径。在这种情况下,您应该
使用sys.argv[0]
sys.argv[0]
当文件为 .exe 并且您运行脚本时,会给出文件的路径python script.py
这就是我目前引用事物的方式
os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'Resources')
这里有更多关于为什么会发生这种情况的详细信息
解决方案 10:
我花了很长时间才找到这个问题的答案,但我终于明白了(其实它真的很简单):
import sys
import os
sys.path.append(os.getcwd() + '/your/subfolder/of/choice')
# now import whatever other modules you want, both the standard ones,
# as the ones supplied in your subfolders
这会将子文件夹的相对路径附加到 python 要查找的目录中。这非常快捷且粗糙,但效果很好:)
扫码咨询,免费领取项目管理大礼包!