使用代码存储库时如何引用资源的相对路径


187

我们正在使用一个代码存储库,该代码存储库同时部署到Windows和Linux中-有时位于不同的目录中。项目内部的模块之一应如何引用项目中的非Python资源之一(CSV文件等)?

如果我们做类似的事情:

thefile=open('test.csv')

要么:

thefile=open('../somedirectory/test.csv')

仅当脚本从一个特定目录或目录的子集运行时,它才起作用。

我想做的是这样的:

path=getBasePathOfProject()+'/somedirectory/test.csv'
thefile=open(path)

可能吗?

Answers:


255

尝试使用相对于当前文件路径的文件名。“ ./my_file”的示例:

fn = os.path.join(os.path.dirname(__file__), 'my_file')

在Python 3.4+中,您还可以使用pathlib

fn = pathlib.Path(__file__).parent / 'my_file'

3
我认为该解决方案仅在资源位于python文件的相同目录或其子目录中时才有效。当您具有以下树结构时,如何解决该问题:/ Project_Root_dir / python_files_dir /此处有更多子目录py_file.py / resources /此处有一些子目录resource_file.csv
olamundo

1
抱歉,文件树在最后一条消息上显示为乱码...第二次尝试:您的文件位于/Project_Root_dir/python_files_dir/some_subdirs/py_file.py,资源文件位于/Project_Root_dir/resources/some_subdirs/resource_file.csv
olamundo 09年

28
您应该能够使用join(foo,'..')进入父目录。因此,从/ root / python_files / module / myfile中,使用os.path.join(os.path.dirname(__file__),'..','..','resources')
c089 2009年

7
os.pardir比稍好一点'..',尽管两者在POSIX和Windows上都是等效的。
davidchambers,2013年

4
@cedbeu:在我遇到的每个系统上它都是等效的,我认为今天每个系统python都可以运行(如果我在这里错了,请更正我)。但是,如果您希望将来将python移植到使用其他路径分隔符的系统上,并希望您的代码已准备就绪,则os.pardir会更易于移植。我假设每个程序员,甚至是一个从未读过任何python的程序员都知道“ ..”的含义,而“ os.pardir”是一种间接的级别,人们必须在文档中查找,所以我个人d坚持“ ..”。
c089

40

如果您使用安装工具或分发(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")

优点是,即使是像鸡蛋一样的存档发行版,它也可以保证正常工作。

请参阅http://packages.python.org/distribute/pkg_resources.html#resourcemanager-api


3
我知道这是一个古老的答案,我的首选方式是使用pkg_resources(可能是?),但是随着压缩鸡蛋的消失,__file__像过去的美好时光那样使用会有什么危害吗?
皮克勒

1
这是一个可靠的方法。即使egg约定不复存在,setuptools并没有,而且许多工具仍在针对在运行时构建egg的git repos安装deps
Deepelement

18

在Python中,路径是相对于当前工作目录的,在大多数情况下,该目录是您运行程序的目录。在当前的工作目录很可能不是同你的模块文件的目录,所以使用相对路径至当前的模块文件始终是一个不错的选择。

使用绝对路径应该是最好的解决方案:

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')

15

我经常使用与此类似的东西:

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())。更多信息在这里


3
不过,很少有用例cwd是模块的路径
cedbeu 2013年

它仅在脚本设置的相同目录(或工作目录)中无法在包内运行。
亚历山德拉(亚历山大)

如果用户使用来自不同目录的绝对路径运行程序,则此方法将无效。例如python3 /usr/someone/test.py
sgrpwr

2

您可以使用内置__file__变量。它包含当前文件的路径。我将在您项目的根目录下的模块中实现getBaseOfProject。在那里,我将获得路径的一部分__file__并将其返回。然后,可以在项目的任何地方使用此方法。


0

我在这里有点难过 想要将一些资源文件打包到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创建了一个weel。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, \
            'mscoco_complete_label_map.pbtxt')
        s = open(file_path, 'r').read()

而且有效。


-5

我花了很长时间弄清楚这个问题的答案,但是我终于明白了(实际上很简单):

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的目录中,这看起来既快速又肮脏,但它的工作原理很像:)


6
仅当您从与所讨论的.py文件相同的目录中运行Python程序时,此方法才有效。在这种情况下,您仍然可以执行open('your/subfolder/of/choice')任何操作。
Paul Fisher

4
OP提到代码需要在Windows和Linux上都可以工作。不会的。
user183037 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.